PageSourceSearch

https://blog.coach.me/wp-content/plugins/ht-mega-for-elementor/assets/js/magnifier.js?ver=3.2.6

js coach.me collected 2026-09-24 08:56:55 UTC 15,628 bytes, 343 lines download raw bytes

1/*!
2 * jQuery Magnify Plugin v2.3.3 by T. H. Doan (https://thdoan.github.io/magnify/)
3 * Based on http://thecodeplayer.com/walkthrough/magnifying-glass-for-images-using-jquery-and-css3
4 *
5 * jQuery Magnify by T. H. Doan is licensed under the MIT License.
6 * Read a copy of the license in the LICENSE file or at https://choosealicense.com/licenses/mit/
7 */
8
9(function($) {
10    $.fn.magnify = function(oOptions) {
11      // Default options
12      oOptions = $.extend({
13        'src': '',
14        'speed': 100,
15        'timeout': -1,
16        'touchBottomOffset': 0,
17        'finalWidth': null,
18        'finalHeight': null,
19        'magnifiedWidth': null,
20        'magnifiedHeight': null,
21        'limitBounds': false,
22        'mobileCloseEvent': 'touchstart',
23        'afterLoad': function(){}
24      }, oOptions);
25  
26      var $that = this, // Preserve scope
27        $html = $('html'),
28  
29        // Initiate
30        init = function(el) {
31          var $image = $(el),
32            $anchor = $image.closest('a'),
33            oDataAttr = {};
34  
35          // Get data attributes
36          for (var i in oOptions) {
37            oDataAttr[i] = $image.attr('data-magnify-' + i.toLowerCase());
38          }
39  
40          // Disable zooming if no valid large image source
41          var sZoomSrc = oDataAttr['src'] || oOptions['src'] || $anchor.attr('href') || '';
42          if (!sZoomSrc) return;
43  
44          var $container,
45            $lens,
46            nImageWidth,
47            nImageHeight,
48            nMagnifiedWidth,
49            nMagnifiedHeight,
50            nLensWidth,
51            nLensHeight,
52            nBoundX = 0,
53            nBoundY = 0,
54            nPosX, nPosY,     // Absolute cursor position
55            nX, nY,           // Relative cursor position
56            oContainerOffset, // Relative to document
57            oImageOffset,     // Relative to container
58            // Get true offsets
59            getOffset = function() {
60              var o = $container.offset();
61              // Store offsets from container border to image inside
62              // NOTE: .offset() does NOT take into consideration image border and padding.
63              oImageOffset = {
64                'top': ($image.offset().top-o.top) + parseInt($image.css('border-top-width')) + parseInt($image.css('padding-top')),
65                'left': ($image.offset().left-o.left) + parseInt($image.css('border-left-width')) + parseInt($image.css('padding-left'))
66              };
67              o.top += oImageOffset['top'];
68              o.left += oImageOffset['left'];
69              return o;
70            },
71            // Hide the lens
72            hideLens = function() {
73              if ($lens.is(':visible')) $lens.fadeOut(oOptions['speed'], function() {
74                $html.removeClass('magnifying').trigger('magnifyend'); // Reset overflow-x
75              });
76            },
77            moveLens = function(e) {
78              // Reinitialize if image initially hidden
79              if (!nImageHeight) {
80                refresh();
81                return;
82              }
83              if (e) {
84                e.preventDefault();
85                // Save last coordinates in case we need to call this function directly (required when
86                // updating magnifiedWidth/magnifiedHeight while the lens is visible).
87                nPosX = e.pageX || e.originalEvent.touches[0].pageX;
88                nPosY = e.pageY || e.originalEvent.touches[0].pageY;
89                $image.data('lastPos', {
90                  'x': nPosX,
91                  'y': nPosY
92                });
93              } else {
94                nPosX = $image.data('lastPos').x;
95                nPosY = $image.data('lastPos').y;
96              }
97              // x/y coordinates of the mouse pointer or touch point. This is the position of
98              // .magnify relative to the document.
99              //
100              // We deduct the positions of .magnify from the mouse or touch positions relative to
101              // the document to get the mouse or touch positions relative to the container.
102              nX = nPosX - oContainerOffset['left'],
103              nY = (nPosY - oContainerOffset['top']) - oOptions['touchBottomOffset'];
104              // Toggle magnifying lens
105              if (!$lens.is(':animated')) {
106                if (nX>nBoundX && nX<nImageWidth-nBoundX && nY>nBoundY && nY<nImageHeight-nBoundY) {
107                  if ($lens.is(':hidden')) {
108                    $html.addClass('magnifying').trigger('magnifystart'); // Hide overflow-x while zooming
109                    $lens.fadeIn(oOptions['speed']);
110                  }
111                } else {
112                  hideLens();
113                }
114              }
115              if ($lens.is(':visible')) {
116                // Move the magnifying lens with the mouse
117                var sBgPos = '';
118                if (nMagnifiedWidth && nMagnifiedHeight) {
119                  // Change the background position of .magnify-lens according to the position of
120                  // the mouse over the .magnify-image image. This allows us to get the ratio of
121                  // the pixel under the mouse pointer with respect to the image and use that to
122                  // position the large image inside the magnifying lens.
123                  var nRatioX = -Math.round(nX/nImageWidth*nMagnifiedWidth-nLensWidth/2),
124                    nRatioY = -Math.round(nY/nImageHeight*nMagnifiedHeight-nLensHeight/2);
125                  if (oOptions['limitBounds']) {
126                    // Enforce bounds to ensure only image is visible in lens
127                    var nBoundRight = -Math.round((nImageWidth-nBoundX)/nImageWidth*nMagnifiedWidth-nLensWidth/2),
128                      nBoundBottom = -Math.round((nImageHeight-nBoundY)/nImageHeight*nMagnifiedHeight-nLensHeight/2);
129                    // Left and right edges
130                    if (nRatioX>0) nRatioX = 0;
131                    else if (nRatioX<nBoundRight) nRatioX = nBoundRight;
132                    // Top and bottom edges
133                    if (nRatioY>0) nRatioY = 0;
134                    else if (nRatioY<nBoundBottom) nRatioY = nBoundBottom;
135                  }
136                  sBgPos = nRatioX + 'px ' + nRatioY + 'px';
137                }
138                // Now the lens moves with the mouse. The logic is to deduct half of the lens's
139                // width and height from the mouse coordinates to place it with its center at the
140                // mouse coordinates. If you hover on the image now, you should see the magnifying
141                // lens in action.
142                $lens.css({
143                  'top': Math.round(nY-nLensHeight/2) + oImageOffset['top'] + 'px',
144                  'left': Math.round(nX-nLensWidth/2) + oImageOffset['left'] + 'px',
145                  'background-position': sBgPos
146                });
147              }
148            };
149  
150          // Data attributes have precedence over options object
151          if (!isNaN(+oDataAttr['speed'])) oOptions['speed'] = +oDataAttr['speed'];
152          if (!isNaN(+oDataAttr['timeout'])) oOptions['timeout'] = +oDataAttr['timeout'];
153          if (!isNaN(+oDataAttr['finalWidth'])) oOptions['finalWidth'] = +oDataAttr['finalWidth'];
154          if (!isNaN(+oDataAttr['finalHeight'])) oOptions['finalHeight'] = +oDataAttr['finalHeight'];
155          if (!isNaN(+oDataAttr['magnifiedWidth'])) oOptions['magnifiedWidth'] = +oDataAttr['magnifiedWidth'];
156          if (!isNaN(+oDataAttr['magnifiedHeight'])) oOptions['magnifiedHeight'] = +oDataAttr['magnifiedHeight'];
157          if (oDataAttr['limitBounds']==='true') oOptions['limitBounds'] = true;
158          if (typeof window[oDataAttr['afterLoad']]==='function') oOptions.afterLoad = window[oDataAttr['afterLoad']];
159  
160          // Implement touch point bottom offset only on mobile devices
161          if (/\b(Android|BlackBerry|IEMobile|iPad|iPhone|Mobile|Opera Mini)\b/.test(navigator.userAgent)) {
162            if (!isNaN(+oDataAttr['touchBottomOffset'])) oOptions['touchBottomOffset'] = +oDataAttr['touchBottomOffset'];
163          } else {
164            oOptions['touchBottomOffset'] = 0;
165          }
166  
167          // Save any inline styles for resetting
168          $image.data('originalStyle', $image.attr('style'));
169  
170          // Activate magnification:
171          // 1. Try to get large image dimensions
172          // 2. Proceed only if able to get large image dimensions OK
173  
174          // [1] Calculate the native (magnified) image dimensions. The zoomed version is only shown
175          // after the native dimensions are available. To get the actual dimensions we have to create
176          // this image object.
177          var elZoomImage = new Image();
178          $(elZoomImage).on({
179            'load': function() {
180              // [2] Got image dimensions OK.
181  
182              // Fix overlap bug at the edges during magnification
183              $image.css('display', 'block');
184              // Create container div if necessary
185              if (!$image.parent('.magnify').length) {
186                $image.wrap('<div class="magnify"></div>');
187              }
188              $container = $image.parent('.magnify');
189              // Create the magnifying lens div if necessary
190              if ($image.prev('.magnify-lens').length) {
191                $container.children('.magnify-lens').css('background-image', 'url(\'' + sZoomSrc + '\')');
192              } else {
193                $image.before('<div class="magnify-lens loading" style="background:url(\'' + sZoomSrc + '\') 0 0 no-repeat"></div>');
194              }
195              $lens = $container.children('.magnify-lens');
196              // Remove the "Loading..." text
197              $lens.removeClass('loading');
198              // Cache dimensions and offsets for improved performance
199              // NOTE: This code is inside the load() function, which is important. The width and
200              // height of the object would return 0 if accessed before the image is fully loaded.
201              nImageWidth = oOptions['finalWidth'] || $image.width();
202              nImageHeight = oOptions['finalHeight'] || $image.height();
203              nMagnifiedWidth = oOptions['magnifiedWidth'] || elZoomImage.width;
204              nMagnifiedHeight = oOptions['magnifiedHeight'] || elZoomImage.height;
205              nLensWidth = $lens.width();
206              nLensHeight = $lens.height();
207              oContainerOffset = getOffset(); // Required by refresh()
208              // Set zoom boundaries
209              if (oOptions['limitBounds']) {
210                nBoundX = (nLensWidth/2) / (nMagnifiedWidth/nImageWidth);
211                nBoundY = (nLensHeight/2) / (nMagnifiedHeight/nImageHeight);
212              }
213              // Enforce non-native large image size?
214              if (nMagnifiedWidth!==elZoomImage.width || nMagnifiedHeight!==elZoomImage.height) {
215                $lens.css('background-size', nMagnifiedWidth + 'px ' + nMagnifiedHeight + 'px');
216              }
217              // Store zoom dimensions for mobile plugin
218              $image.data('zoomSize', {
219                'width': nMagnifiedWidth,
220                'height': nMagnifiedHeight
221              });
222              // Store mobile close event for mobile plugin
223              $container.data('mobileCloseEvent', oDataAttr['mobileCloseEvent'] || oOptions['mobileCloseEvent']);
224              // Clean up
225              elZoomImage = null;
226              // Execute callback
227              oOptions.afterLoad();
228              // Simulate a lens move to update positioning if magnifiedWidth/magnifiedHeight is
229              // updated while the lens is visible
230              if ($lens.is(':visible')) moveLens();
231              // Handle mouse movements
232              $container.off().on({
233                'mousemove touchmove': moveLens,
234                'mouseenter': function() {
235                  // Need to update offsets here to support accordions
236                  oContainerOffset = getOffset();
237                },
238                'mouseleave': hideLens
239              });
240  
241              // Prevent magnifying lens from getting "stuck"
242              if (oOptions['timeout']>=0) {
243                $container.on('touchend', function() {
244                  setTimeout(hideLens, oOptions['timeout']);
245                });
246              }
247              // Ensure lens is closed when tapping outside of it
248              $('body').not($container).on('touchstart', hideLens);
249  
250              // Support image map click-throughs while zooming
251              var sUsemap = $image.attr('usemap');
252              if (sUsemap) {
253                var $map = $('map[name=' + sUsemap.slice(1) + ']');
254                // Image map needs to be on the same DOM level as image source
255                $image.after($map);
256                $container.click(function(e) {
257                  // Trigger click on image below lens at current cursor position
258                  if (e.clientX || e.clientY) {
259                    $lens.hide();
260                    var elPoint = document.elementFromPoint(
261                        e.clientX || e.originalEvent.touches[0].clientX,
262                        e.clientY || e.originalEvent.touches[0].clientY
263                      );
264                    if (elPoint.nodeName==='AREA') {
265                      elPoint.click();
266                    } else {
267                      // Workaround for buggy implementation of elementFromPoint()
268                      // See https://bugzilla.mozilla.org/show_bug.cgi?id=1227469
269                      $('area', $map).each(function() {
270                        var a = $(this).attr('coords').split(',');
271                        if (nX>=a[0] && nX<=a[2] && nY>=a[1] && nY<=a[3]) {
272                          this.click();
273                          return false;
274                        }
275                      });
276                    }
277                  }
278                });
279              }
280  
281              if ($anchor.length) {
282                // Make parent anchor inline-block to have correct dimensions
283                $anchor.css('display', 'inline-block');
284                // Disable parent anchor if it's sourcing the large image
285                if ($anchor.attr('href') && !(oDataAttr['src'] || oOptions['src'])) {
286                  $anchor.click(function(e) {
287                    e.preventDefault();
288                  });
289                }
290              }
291  
292            },
293            'error': function() {
294              // Clean up
295              elZoomImage = null;
296            }
297          });
298  
299          elZoomImage.src = sZoomSrc;
300        }, // END init()
301  
302        // Simple debounce
303        nTimer = 0,
304        refresh = function() {
305          clearTimeout(nTimer);
306          nTimer = setTimeout(function() {
307            $that.destroy();
308            $that.magnify(oOptions);
309          }, 100);
310        };
311  
312      /**
313       * Public Methods
314       */
315  
316      // Turn off zoom and reset to original state
317      this.destroy = function() {
318        this.each(function() {
319          var $this = $(this),
320            $lens = $this.prev('div.magnify-lens'),
321            sStyle = $this.data('originalStyle');
322          if ($this.parent('div.magnify').length && $lens.length) {
323            if (sStyle) $this.attr('style', sStyle);
324            else $this.removeAttr('style');
325            $this.unwrap();
326            $lens.remove();
327          }
328        });
329        // Unregister event handler
330        $(window).off('resize', refresh);
331        return $that;
332      }
333  
334      // Handle window resizing
335      $(window).resize(refresh);
336  
337      return this.each(function() {
338        // Initiate magnification powers
339        init(this);
340      });
341  
342    };
343  }(jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.