'apply a svg clipPath polygon on a zoomed image

I built an image composed of multiple logos in low resolution. I also built the same image in high resolution (6 times bigger).

I present the low-res image on the homepage and apply on it a zoom plugin (this one : https://github.com/thdoan/magnify).

I pass to this plugin the image hi-res and it gives a nice magnifying glass on each logo and display them in high resolution.

I have on the same page the ability to make a search by name of the logo. My backend sends the result with the list of the logos to display as a result of the search.

To make it happen, I apply a svg polygon clipPath on the right dimension of each logo in the result.

My issue is that the zoom plugin disappear when the result of the search is returned. And I don't succeed to make the following things:

  1. to let the zoom applied even after the search event
  2. apply the svg for the hi-res image

someone can help?

html page:

<svg id="mysvg" width="0" height="0">
  <defs>
    <clipPath id="myClip"></clipPath>
  </defs>
</svg>
<svg id="mysvgBig" width="0" height="0">
  <defs>
    <clipPath id="myClipBig"></clipPath>
  </defs>
</svg>
<div id="clickzone" class="magnify">
  <div style="width: 900px; height: 900px; background-image:url(static/assets/displayFlag.png); background-size: cover;">
    <img id="imgLogos" src="static/assets/view_D_tr.png'" class="zoom" data-magnify-src="static/assets/view_M_tr.png" >
  </div>
</div>

my CSS:

    .clip-svg {
  clip-path: url(#myClip);
}

.clip-svg-big {
  clip-path: url(#myClipBig);
}

my JS function for svg:

    function maskMe (result) {
    var imglog = document.getElementById("imgLogos");
    var imglogbig = document.getElementById("imgLogosBig");
    var clipPath = document.getElementById("myClip");
    var clipPathBig = document.getElementById("myClipBig");
    if (result.length == 0) {
        console.log("no result")
        clipPath.innerHTML = "";
        clipPathBig.innerHTML = "";
        imglog.classList.add("clip-svg");
        imglogbig.classList.add("clip-svg-big");
    }else if (result.length == 1 && result[0].all == 'all') {
        console.log("all")
        imglog.classList.remove("clip-svg");
        clipPath.innerHTML = "";
        imglogbig.classList.remove("clip-svg-big");
        clipPathBig.innerHTML = "";
    }else {
        const coordBig = [];
        const coord = result.map(item => {
            console.log("with result")
            coordBig.push('<polygon points="'+ (item.x*6) + ',' + (item.y*6) + ' ' + ((item.x + item.pixelCols)*6) + ',' + (item.y*6) + ' ' + ((item.x + item.pixelCols)*6) + ',' + ((item.y + item.pixelRows)*6) + ' ' + (item.x*6) + ',' + ((item.y + item.pixelRows)*6) + '"></polygon>')
            return '<polygon points="'+ item.x + ',' + item.y + ' ' + (item.x + item.pixelCols) + ',' + item.y + ' ' + (item.x + item.pixelCols) + ',' + (item.y + item.pixelRows) + ' ' + item.x + ',' + (item.y + item.pixelRows) + '"></polygon>';
        })

        imglog.classList.add("clip-svg");
        imglogbig.classList.add("clip-svg-big");
        for (let i=0; i<coord.length; i++){
            myClip = coord.join("")
        }
        for (let i=0; i<coordBig.length; i++){
            myClipBig = coordBig.join("")
        }
        clipPath.innerHTML = myClip;
        clipPathBig.innerHTML = myClipBig;
    }
}

the plugin jquery code:

(function($) {
  $.fn.magnify = function(oOptions) {
    // Default options
    oOptions = $.extend({
      'src': '',
      'speed': 100,
      'timeout': -1,
      'touchBottomOffset': 0,
      'finalWidth': null,
      'finalHeight': null,
      'magnifiedWidth': null,
      'magnifiedHeight': null,
      'limitBounds': false,
      'mobileCloseEvent': 'touchstart',
      'afterLoad': function(){}
    }, oOptions);

    var $that = this, // Preserve scope
      $html = $('html'),

      // Initiate
      init = function(el) {
        var $image = $(el),
          $anchor = $image.closest('a'),
          oDataAttr = {};

        // Get data attributes
        for (var i in oOptions) {
          oDataAttr[i] = $image.attr('data-magnify-' + i.toLowerCase());
        }

        // Disable zooming if no valid large image source
        var sZoomSrc = oDataAttr['src'] || oOptions['src'] || $anchor.attr('href') || '';
        if (!sZoomSrc) return;

        var $container,
          $lens,
          nImageWidth,
          nImageHeight,
          nMagnifiedWidth,
          nMagnifiedHeight,
          nLensWidth,
          nLensHeight,
          nBoundX = 0,
          nBoundY = 0,
          nPosX, nPosY,     // Absolute cursor position
          nX, nY,           // Relative cursor position
          oContainerOffset, // Relative to document
          oImageOffset,     // Relative to container
          // Get true offsets
          getOffset = function() {
            var o = $container.offset();
            // Store offsets from container border to image inside
            // NOTE: .offset() does NOT take into consideration image border and padding.
            oImageOffset = {
              'top': ($image.offset().top-o.top) + parseInt($image.css('border-top-width')) + parseInt($image.css('padding-top')),
              'left': ($image.offset().left-o.left) + parseInt($image.css('border-left-width')) + parseInt($image.css('padding-left'))
            };
            o.top += oImageOffset['top'];
            o.left += oImageOffset['left'];
            return o;
          },
          // Hide the lens
          hideLens = function() {
            if ($lens.is(':visible')) $lens.fadeOut(oOptions['speed'], function() {
              $html.removeClass('magnifying').trigger('magnifyend'); // Reset overflow-x
            });
          },
          moveLens = function(e) {
            // Reinitialize if image initially hidden
            if (!nImageHeight) {
              refresh();
              return;
            }
            if (e) {
              e.preventDefault();
              // Save last coordinates in case we need to call this function directly (required when
              // updating magnifiedWidth/magnifiedHeight while the lens is visible).
              nPosX = e.pageX || e.originalEvent.touches[0].pageX;
              nPosY = e.pageY || e.originalEvent.touches[0].pageY;
              $image.data('lastPos', {
                'x': nPosX,
                'y': nPosY
              });
            } else {
              nPosX = $image.data('lastPos').x;
              nPosY = $image.data('lastPos').y;
            }
            // x/y coordinates of the mouse pointer or touch point. This is the position of
            // .magnify relative to the document.
            //
            // We deduct the positions of .magnify from the mouse or touch positions relative to
            // the document to get the mouse or touch positions relative to the container.
            nX = nPosX - oContainerOffset['left'],
            nY = (nPosY - oContainerOffset['top']) - oOptions['touchBottomOffset'];
            // Toggle magnifying lens
            if (!$lens.is(':animated')) {
              if (nX>nBoundX && nX<nImageWidth-nBoundX && nY>nBoundY && nY<nImageHeight-nBoundY) {
                if ($lens.is(':hidden')) {
                  $html.addClass('magnifying').trigger('magnifystart'); // Hide overflow-x while zooming
                  $lens.fadeIn(oOptions['speed']);
                }
              } else {
                hideLens();
              }
            }
            if ($lens.is(':visible')) {
              // Move the magnifying lens with the mouse
              var sBgPos = '';
              if (nMagnifiedWidth && nMagnifiedHeight) {
                // Change the background position of .magnify-lens according to the position of
                // the mouse over the .magnify-image image. This allows us to get the ratio of
                // the pixel under the mouse pointer with respect to the image and use that to
                // position the large image inside the magnifying lens.
                var nRatioX = -Math.round(nX/nImageWidth*nMagnifiedWidth-nLensWidth/2),
                  nRatioY = -Math.round(nY/nImageHeight*nMagnifiedHeight-nLensHeight/2);
                if (oOptions['limitBounds']) {
                  // Enforce bounds to ensure only image is visible in lens
                  var nBoundRight = -Math.round((nImageWidth-nBoundX)/nImageWidth*nMagnifiedWidth-nLensWidth/2),
                    nBoundBottom = -Math.round((nImageHeight-nBoundY)/nImageHeight*nMagnifiedHeight-nLensHeight/2);
                  // Left and right edges
                  if (nRatioX>0) nRatioX = 0;
                  else if (nRatioX<nBoundRight) nRatioX = nBoundRight;
                  // Top and bottom edges
                  if (nRatioY>0) nRatioY = 0;
                  else if (nRatioY<nBoundBottom) nRatioY = nBoundBottom;
                }
                sBgPos = nRatioX + 'px ' + nRatioY + 'px';
              }
              // Now the lens moves with the mouse. The logic is to deduct half of the lens's
              // width and height from the mouse coordinates to place it with its center at the
              // mouse coordinates. If you hover on the image now, you should see the magnifying
              // lens in action.
              $lens.css({
                'top': Math.round(nY-nLensHeight/2) + oImageOffset['top'] + 'px',
                'left': Math.round(nX-nLensWidth/2) + oImageOffset['left'] + 'px',
                'background-position': sBgPos
              });
            }
          };

        // Data attributes have precedence over options object
        if (!isNaN(+oDataAttr['speed'])) oOptions['speed'] = +oDataAttr['speed'];
        if (!isNaN(+oDataAttr['timeout'])) oOptions['timeout'] = +oDataAttr['timeout'];
        if (!isNaN(+oDataAttr['finalWidth'])) oOptions['finalWidth'] = +oDataAttr['finalWidth'];
        if (!isNaN(+oDataAttr['finalHeight'])) oOptions['finalHeight'] = +oDataAttr['finalHeight'];
        if (!isNaN(+oDataAttr['magnifiedWidth'])) oOptions['magnifiedWidth'] = +oDataAttr['magnifiedWidth'];
        if (!isNaN(+oDataAttr['magnifiedHeight'])) oOptions['magnifiedHeight'] = +oDataAttr['magnifiedHeight'];
        if (oDataAttr['limitBounds']==='true') oOptions['limitBounds'] = true;
        if (typeof window[oDataAttr['afterLoad']]==='function') oOptions.afterLoad = window[oDataAttr['afterLoad']];

        // Implement touch point bottom offset only on mobile devices
        if (/\b(Android|BlackBerry|IEMobile|iPad|iPhone|Mobile|Opera Mini)\b/.test(navigator.userAgent)) {
          if (!isNaN(+oDataAttr['touchBottomOffset'])) oOptions['touchBottomOffset'] = +oDataAttr['touchBottomOffset'];
        } else {
          oOptions['touchBottomOffset'] = 0;
        }

        // Save any inline styles for resetting
        $image.data('originalStyle', $image.attr('style'));

        // Activate magnification:
        // 1. Try to get large image dimensions
        // 2. Proceed only if able to get large image dimensions OK

        // [1] Calculate the native (magnified) image dimensions. The zoomed version is only shown
        // after the native dimensions are available. To get the actual dimensions we have to create
        // this image object.
        var elZoomImage = new Image();
        $(elZoomImage).on({
          'load': function() {
            // [2] Got image dimensions OK.

            // Fix overlap bug at the edges during magnification
            $image.css('display', 'block');
            // Create container div if necessary
           if (!$image.parent('.magnify').length) {
              $image.wrap('<div class="magnify"></div>');
           }
            $container = $image.parent('.magnify');
            // Create the magnifying lens div if necessary
            if ($image.prev('.magnify-lens').length) {
              $container.children('.magnify-lens').css('background-image', 'url(\'' + sZoomSrc + '\')');
            } else {
              //I add the id="imgLogosBig" to apply a svg on the hi-res image
              $image.before('<div id="imgLogosBig" class="magnify-lens loading" style="background:url(\'' + sZoomSrc + '\') 0 0 no-repeat"></div>');
            }
            $lens = $container.children('.magnify-lens');
            // Remove the "Loading..." text
            $lens.removeClass('loading');
            // Cache dimensions and offsets for improved performance
            // NOTE: This code is inside the load() function, which is important. The width and
            // height of the object would return 0 if accessed before the image is fully loaded.
            nImageWidth = oOptions['finalWidth'] || $image.width();
            nImageHeight = oOptions['finalHeight'] || $image.height();
            nMagnifiedWidth = oOptions['magnifiedWidth'] || elZoomImage.width;
            nMagnifiedHeight = oOptions['magnifiedHeight'] || elZoomImage.height;
            nLensWidth = $lens.width();
            nLensHeight = $lens.height();
            oContainerOffset = getOffset(); // Required by refresh()
            // Set zoom boundaries
            if (oOptions['limitBounds']) {
              nBoundX = (nLensWidth/2) / (nMagnifiedWidth/nImageWidth);
              nBoundY = (nLensHeight/2) / (nMagnifiedHeight/nImageHeight);
            }
            // Enforce non-native large image size?
            if (nMagnifiedWidth!==elZoomImage.width || nMagnifiedHeight!==elZoomImage.height) {
              $lens.css('background-size', nMagnifiedWidth + 'px ' + nMagnifiedHeight + 'px');
            }
            // Store zoom dimensions for mobile plugin
            $image.data('zoomSize', {
              'width': nMagnifiedWidth,
              'height': nMagnifiedHeight
            });
            // Store mobile close event for mobile plugin
            $container.data('mobileCloseEvent', oDataAttr['mobileCloseEvent'] || oOptions['mobileCloseEvent']);
            // Clean up
            elZoomImage = null;
            // Execute callback
            oOptions.afterLoad();
            // Simulate a lens move to update positioning if magnifiedWidth/magnifiedHeight is
            // updated while the lens is visible
            if ($lens.is(':visible')) moveLens();
            // Handle mouse movements
            $container.off().on({
              'mousemove touchmove': moveLens,
              'mouseenter': function() {
                // Need to update offsets here to support accordions
                oContainerOffset = getOffset();
              },
              'mouseleave': hideLens
            });

            // Prevent magnifying lens from getting "stuck"
            if (oOptions['timeout']>=0) {
              $container.on('touchend', function() {
                setTimeout(hideLens, oOptions['timeout']);
              });
            }
            // Ensure lens is closed when tapping outside of it
            $('body').not($container).on('touchstart', hideLens);

            // Support image map click-throughs while zooming
            var sUsemap = $image.attr('usemap');
            if (sUsemap) {
              var $map = $('map[name=' + sUsemap.slice(1) + ']');
              // Image map needs to be on the same DOM level as image source
              $image.after($map);
              $container.click(function(e) {
                // Trigger click on image below lens at current cursor position
                if (e.clientX || e.clientY) {
                  $lens.hide();
                  var elPoint = document.elementFromPoint(
                      e.clientX || e.originalEvent.touches[0].clientX,
                      e.clientY || e.originalEvent.touches[0].clientY
                    );
                  if (elPoint.nodeName==='AREA') {
                    elPoint.click();
                  } else {
                    // Workaround for buggy implementation of elementFromPoint()
                    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1227469
                    $('area', $map).each(function() {
                      var a = $(this).attr('coords').split(',');
                      if (nX>=a[0] && nX<=a[2] && nY>=a[1] && nY<=a[3]) {
                        this.click();
                        return false;
                      }
                    });
                  }
                }
              });
            }

            if ($anchor.length) {
              // Make parent anchor inline-block to have correct dimensions
              $anchor.css('display', 'inline-block');
              // Disable parent anchor if it's sourcing the large image
              if ($anchor.attr('href') && !(oDataAttr['src'] || oOptions['src'])) {
                $anchor.click(function(e) {
                  e.preventDefault();
                });
              }
            }

          },
          'error': function() {
            // Clean up
            elZoomImage = null;
          }
        });

        elZoomImage.src = sZoomSrc;
      }, // END init()

      // Simple debounce
      nTimer = 0,
      refresh = function() {
        clearTimeout(nTimer);
        nTimer = setTimeout(function() {
          $that.destroy();
          $that.magnify(oOptions);
        }, 100);
      };

    /**
     * Public Methods
     */

    // Turn off zoom and reset to original state
    this.destroy = function() {
      this.each(function() {
        var $this = $(this),
          $lens = $this.prev('div.magnify-lens'),
          sStyle = $this.data('originalStyle');
        if ($this.parent('div.magnify').length && $lens.length) {
          if (sStyle) $this.attr('style', sStyle);
          else $this.removeAttr('style');
          $this.unwrap();
          $lens.remove();
        }
      });
      // Unregister event handler
      $(window).off('resize', refresh);
      return $that;
    }

    // Handle window resizing
    $(window).resize(refresh);

    return this.each(function() {
      // Initiate magnification powers
      init(this);
    });

  };}
(jQuery));


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source