PageSourceSearch

https://www.amiens.fr/extension/amiens/design/amiens/javascript/easyzoom.js

js amiens.fr collected 2026-10-01 10:18:47 UTC 9,362 bytes, 342 lines download raw bytes

vendor: 9,362 bytes, lines 1-342
1(function (root, factory) {
2    'use strict';
3    if(typeof define === 'function' && define.amd) {
4        define(['jquery'], function($){
5            factory($);
6        });
7    } else if(typeof module === 'object' && module.exports) {
8        module.exports = (root.EasyZoom = factory(require('jquery')));
9    } else {
10        root.EasyZoom = factory(root.jQuery);
11    }
12}(this, function ($) {
13
14    'use strict';
15
16    var zoomImgOverlapX;
17    var zoomImgOverlapY;
18    var ratioX;
19    var ratioY;
20    var pointerPositionX;
21    var pointerPositionY;
22
23    var defaults = {
24
25        // The text to display within the notice box while loading the zoom image.
26        loadingNotice: 'Loading image',
27
28        // The text to display within the notice box if an error occurs when loading the zoom image.
29        errorNotice: 'The image could not be loaded',
30
31        // The time (in milliseconds) to display the error notice.
32        errorDuration: 2500,
33
34        // Attribute to retrieve the zoom image URL from.
35        linkAttribute: 'href',
36
37        // Prevent clicks on the zoom image link.
38        preventClicks: true,
39
40        // Callback function to execute before the flyout is displayed.
41        beforeShow: $.noop,
42
43        // Callback function to execute before the flyout is removed.
44        beforeHide: $.noop,
45
46        // Callback function to execute when the flyout is displayed.
47        onShow: $.noop,
48
49        // Callback function to execute when the flyout is removed.
50        onHide: $.noop,
51
52        // Callback function to execute when the cursor is moved while over the image.
53        onMove: $.noop
54
55    };
56
57    /**
58     * EasyZoom
59     * @constructor
60     * @param {Object} target
61     * @param {Object} options (Optional)
62     */
63    function EasyZoom(target, options) {
64        this.$target = $(target);
65        this.opts = $.extend({}, defaults, options, this.$target.data());
66
67        this.isOpen === undefined && this._init();
68    }
69
70    /**
71     * Init
72     * @private
73     */
74    EasyZoom.prototype._init = function() {
75        this.$link   = this.$target.find('a');
76        this.$image  = this.$target.find('img');
77
78        this.$flyout = $('<div class="easyzoom-flyout" />');
79        this.$notice = $('<div class="easyzoom-notice" />');
80
81        this.$target.on({
82            'mousemove.easyzoom touchmove.easyzoom': $.proxy(this._onMove, this),
83            'mouseleave.easyzoom touchend.easyzoom': $.proxy(this._onLeave, this),
84            'mouseenter.easyzoom touchstart.easyzoom': $.proxy(this._onEnter, this)
85        });
86
87        this.opts.preventClicks && this.$target.on('click.easyzoom', function(e) {
88            e.preventDefault();
89        });
90    };
91
92    /**
93     * Show
94     * @param {MouseEvent|TouchEvent} e
95     * @param {Boolean} testMouseOver (Optional)
96     */
97    EasyZoom.prototype.show = function(e, testMouseOver) {
98        var self = this;
99
100        if (this.opts.beforeShow.call(this) === false) return;
101
102        if (!this.isReady) {
103            return this._loadImage(this.$link.attr(this.opts.linkAttribute), function() {
104                if (self.isMouseOver || !testMouseOver) {
105                    self.show(e);
106                }
107            });
108        }
109
110        this.$target.append(this.$flyout);
111
112        var targetWidth = this.$target.outerWidth();
113        var targetHeight = this.$target.outerHeight();
114
115        var flyoutInnerWidth = this.$flyout.width();
116        var flyoutInnerHeight = this.$flyout.height();
117
118        var zoomImgWidth = this.$zoom.width();
119        var zoomImgHeight = this.$zoom.height();
120
121        zoomImgOverlapX = Math.ceil(zoomImgWidth - flyoutInnerWidth);
122        zoomImgOverlapY = Math.ceil(zoomImgHeight - flyoutInnerHeight);
123
124        // For when the zoom image is smaller than the flyout element.
125        if (zoomImgOverlapX < 0) zoomImgOverlapX = 0;
126        if (zoomImgOverlapY < 0) zoomImgOverlapY = 0;
127
128        ratioX = zoomImgOverlapX / targetWidth;
129        ratioY = zoomImgOverlapY / targetHeight;
130
131        this.isOpen = true;
132
133        this.opts.onShow.call(this);
134
135        e && this._move(e);
136    };
137
138    /**
139     * On enter
140     * @private
141     * @param {Event} e
142     */
143    EasyZoom.prototype._onEnter = function(e) {
144        var touches = e.originalEvent.touches;
145
146        this.isMouseOver = true;
147
148        if (!touches || touches.length == 1) {
149            e.preventDefault();
150            this.show(e, true);
151        }
152    };
153
154    /**
155     * On move
156     * @private
157     * @param {Event} e
158     */
159    EasyZoom.prototype._onMove = function(e) {
160        if (!this.isOpen) return;
161
162        e.preventDefault();
163        this._move(e);
164    };
165
166    /**
167     * On leave
168     * @private
169     */
170    EasyZoom.prototype._onLeave = function() {
171        this.isMouseOver = false;
172        this.isOpen && this.hide();
173    };
174
175    /**
176     * On load
177     * @private
178     * @param {Event} e
179     */
180    EasyZoom.prototype._onLoad = function(e) {
181        // IE may fire a load event even on error so test the image dimensions
182        if (!e.currentTarget.width) return;
183
184        this.isReady = true;
185
186        this.$notice.detach();
187        this.$flyout.html(this.$zoom);
188        this.$target.removeClass('is-loading').addClass('is-ready');
189
190        e.data.call && e.data();
191    };
192
193    /**
194     * On error
195     * @private
196     */
197    EasyZoom.prototype._onError = function() {
198        var self = this;
199
200        this.$notice.text(this.opts.errorNotice);
201        this.$target.removeClass('is-loading').addClass('is-error');
202
203        this.detachNotice = setTimeout(function() {
204            self.$notice.detach();
205            self.detachNotice = null;
206        }, this.opts.errorDuration);
207    };
208
209    /**
210     * Load image
211     * @private
212     * @param {String} href
213     * @param {Function} callback
214     */
215    EasyZoom.prototype._loadImage = function(href, callback) {
216        var zoom = new Image();
217
218        this.$target
219            .addClass('is-loading')
220            .append(this.$notice.text(this.opts.loadingNotice));
221
222        this.$zoom = $(zoom)
223            .on('error', $.proxy(this._onError, this))
224            .on('load', callback, $.proxy(this._onLoad, this));
225
226        zoom.style.position = 'absolute';
227        zoom.src = href;
228    };
229
230    /**
231     * Move
232     * @private
233     * @param {Event} e
234     */
235    EasyZoom.prototype._move = function(e) {
236
237        if (e.type.indexOf('touch') === 0) {
238            var touchlist = e.touches || e.originalEvent.touches;
239            pointerPositionX = touchlist[0].pageX;
240            pointerPositionY = touchlist[0].pageY;
241        } else {
242            pointerPositionX = e.pageX || pointerPositionX;
243            pointerPositionY = e.pageY || pointerPositionY;
244        }
245
246        var targetOffset  = this.$target.offset();
247        var relativePositionX = pointerPositionX - targetOffset.left;
248        var relativePositionY = pointerPositionY - targetOffset.top;
249        var moveX = Math.ceil(relativePositionX * ratioX);
250        var moveY = Math.ceil(relativePositionY * ratioY);
251
252        // Close if outside
253        if (moveX < 0 || moveY < 0 || moveX > zoomImgOverlapX || moveY > zoomImgOverlapY) {
254            this.hide();
255        } else {
256            var top = moveY * -1;
257            var left = moveX * -1;
258
259            if ('transform' in document.body.style) {
260                this.$zoom.css({ transform: 'translate(' + left + 'px, ' + top + 'px)' });
261            } else {
262                this.$zoom.css({ top: top, left: left });
263            }
264
265            this.opts.onMove.call(this, top, left);
266        }
267    };
268
269    /**
270     * Hide
271     */
272    EasyZoom.prototype.hide = function() {
273        if (!this.isOpen) return;
274        if (this.opts.beforeHide.call(this) === false) return;
275
276        this.$flyout.detach();
277        this.isOpen = false;
278
279        this.opts.onHide.call(this);
280    };
281
282    /**
283     * Swap
284     * @param {String} standardSrc
285     * @param {String} zoomHref
286     * @param {String|Array} srcset (Optional)
287     */
288    EasyZoom.prototype.swap = function(standardSrc, zoomHref, srcset) {
289        this.hide();
290        this.isReady = false;
291
292        this.detachNotice && clearTimeout(this.detachNotice);
293
294        this.$notice.parent().length && this.$notice.detach();
295
296        this.$target.removeClass('is-loading is-ready is-error');
297
298        this.$image.attr({
299            src: standardSrc,
300            srcset: $.isArray(srcset) ? srcset.join() : srcset
301        });
302
303        this.$link.attr(this.opts.linkAttribute, zoomHref);
304    };
305
306    /**
307     * Teardown
308     */
309    EasyZoom.prototype.teardown = function() {
310        this.hide();
311
312        this.$target
313            .off('.easyzoom')
314            .removeClass('is-loading is-ready is-error');
315
316        this.detachNotice && clearTimeout(this.detachNotice);
317
318        delete this.$link;
319        delete this.$zoom;
320        delete this.$image;
321        delete this.$notice;
322        delete this.$flyout;
323
324        delete this.isOpen;
325        delete this.isReady;
326    };
327
328    // jQuery plugin wrapper
329    $.fn.easyZoom = function(options) {
330        return this.each(function() {
331            var api = $.data(this, 'easyZoom');
332
333            if (!api) {
334                $.data(this, 'easyZoom', new EasyZoom(this, options));
335            } else if (api.isOpen === undefined) {
336                api._init();
337            }
338        });
339    };
340
341    return EasyZoom;
342}));

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.