compare-images-slider 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,15 +51,27 @@ document.addEventListener('CompareImagesSliderLoaded', function() {
51
51
 
52
52
  ## Options
53
53
 
54
- Coming soon...
54
+ ```javascript
55
+ // Default options
56
+ const options = {
57
+ inertia: false, // inertia physics, you can flick the handle
58
+ friction: 0.9, // the friction of the inertia
59
+ bounce: false, // will bounce back when intertia is enabled and the boundary is reached
60
+ bounceFactor: 0.1, // the force of the bounce
61
+ vertical: false // vertical slider
62
+ onlyHandle: true // only the handle is draggable
63
+ }
64
+
65
+ new CompareImagesSlider(slider, options);
66
+ ```
55
67
 
56
68
  ## TODO:
57
69
 
58
- - [ ] Add options
59
- - [ ] Scroll block on drag
60
- - [ ] Vertical option
61
- - [ ] Add factory class, migrate the general factory class to the book of spells prior to that
62
- - [ ] Refactor onDrag and move it to the book of spells
70
+ - [x] Add options
71
+ - [x] Scroll block on drag
72
+ - [x] Vertical option
73
+ - [ ] Add factory class, migrate the general factory class to the book of spells prior to that? Better turn this into custom element!
74
+ - [x] Refactor onDrag and move it to the book of spells
63
75
  - [ ] Add initialized state, don't initialize twice
64
76
 
65
77
  ---
Binary file
Binary file
Binary file
@@ -1,4 +1,4 @@
1
- /* compare-images-slider v1.0.0 | https://stamat.github.io/compare-images-slider/ | MIT License */
1
+ /* compare-images-slider v1.0.1 | https://stamat.github.io/compare-images-slider/ | MIT License */
2
2
  @charset "UTF-8";
3
3
  :root {
4
4
  --compare-images-slider-initial-position: 50%;
@@ -17,6 +17,7 @@
17
17
  .compare-images-slider > img {
18
18
  max-width: 100%;
19
19
  height: auto;
20
+ display: block;
20
21
  }
21
22
  .compare-images-slider .frame {
22
23
  position: absolute;
@@ -29,6 +30,7 @@
29
30
  }
30
31
  .compare-images-slider .frame > img {
31
32
  height: auto;
33
+ display: block;
32
34
  }
33
35
  .compare-images-slider .handle {
34
36
  position: absolute;
@@ -44,6 +46,7 @@
44
46
  .compare-images-slider .handle:after {
45
47
  position: absolute;
46
48
  top: 50%;
49
+ left: 50%;
47
50
  width: 42px;
48
51
  height: 42px;
49
52
  transform: translate3d(-50%, -50%, 0);
@@ -54,4 +57,20 @@
54
57
  text-align: center;
55
58
  border-radius: 21px;
56
59
  }
60
+ .compare-images-slider[data-vertical] .frame, .compare-images-slider[vertical] .frame {
61
+ width: 100%;
62
+ height: var(--compare-images-slider-initial-position);
63
+ }
64
+ .compare-images-slider[data-vertical] .handle, .compare-images-slider[vertical] .handle {
65
+ left: 0;
66
+ top: var(--compare-images-slider-initial-position);
67
+ width: 100%;
68
+ height: 2px;
69
+ margin-top: -1px;
70
+ margin-left: 0;
71
+ cursor: ns-resize;
72
+ }
73
+ .compare-images-slider[data-vertical] .handle:after, .compare-images-slider[vertical] .handle:after {
74
+ content: "↕";
75
+ }
57
76
  /*# sourceMappingURL=compare-images-slider.css.map */
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["file:///Users/stamat/Sites/localhost/compare-images-slider/src/styles/index.scss"],"names":[],"mappings":";;AAAA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA","sourcesContent":[":root {\n --compare-images-slider-initial-position: 50%;\n}\n\n.compare-images-slider {\n display: block;\n position: relative;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n\n img {\n pointer-events: none;\n }\n\n & > img {\n max-width: 100%;\n height: auto;\n }\n\n .frame {\n position: absolute;\n top:0;\n left: 0;\n height: 100%;\n width: var(--compare-images-slider-initial-position);\n overflow: hidden;\n z-index: 2;\n\n & > img {\n height: auto;\n }\n }\n\n .handle {\n position:absolute;\n left: var(--compare-images-slider-initial-position);\n top:0;\n bottom:0;\n width: 2px;\n margin-left: -1px;\n height: 100%;\n cursor: ew-resize;\n z-index: 3;\n }\n\n .handle:after {\n position: absolute;\n top: 50%;\n width: 42px;\n height: 42px;\n transform: translate3d(-50%, -50%, 0);\n\n content:'↔';\n line-height: 38px;\n font-size: 28px;\n background: #fff;\n text-align: center;\n border-radius: 21px;\n }\n}\n"]}
1
+ {"version":3,"sourceRoot":"","sources":["file:///Users/stamat/Sites/localhost/compare-images-slider/src/styles/index.scss"],"names":[],"mappings":";;AAAA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAKA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE","sourcesContent":[":root {\n --compare-images-slider-initial-position: 50%;\n}\n\n.compare-images-slider {\n display: block;\n position: relative;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n\n img {\n pointer-events: none;\n }\n\n & > img {\n max-width: 100%;\n height: auto;\n display: block;\n }\n\n .frame {\n position: absolute;\n top:0;\n left: 0;\n height: 100%;\n width: var(--compare-images-slider-initial-position);\n overflow: hidden;\n z-index: 2;\n\n & > img {\n height: auto;\n display: block;\n }\n }\n\n .handle {\n position:absolute;\n left: var(--compare-images-slider-initial-position);\n top:0;\n bottom:0;\n width: 2px;\n margin-left: -1px;\n height: 100%;\n cursor: ew-resize;\n z-index: 3;\n }\n\n .handle:after {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 42px;\n height: 42px;\n transform: translate3d(-50%, -50%, 0);\n\n content:'↔';\n line-height: 38px;\n font-size: 28px;\n background: #fff;\n text-align: center;\n border-radius: 21px;\n }\n\n &[data-vertical],\n &[vertical] {\n .frame {\n width: 100%;\n height: var(--compare-images-slider-initial-position);\n }\n\n .handle {\n left: 0;\n top: var(--compare-images-slider-initial-position);\n width: 100%;\n height: 2px;\n margin-top: -1px;\n margin-left: 0;\n cursor: ns-resize;\n }\n\n .handle:after {\n content:'↕';\n }\n }\n}\n"]}
@@ -1,81 +1,177 @@
1
- /* compare-images-slider v1.0.0 | https://stamat.github.io/compare-images-slider/ | MIT License */
1
+ /* compare-images-slider v1.0.1 | https://stamat.github.io/compare-images-slider/ | MIT License */
2
2
  (() => {
3
3
  // node_modules/book-of-spells/src/helpers.mjs
4
+ function shallowMerge(target, source) {
5
+ for (const key in source) {
6
+ target[key] = source[key];
7
+ }
8
+ return target;
9
+ }
10
+ function isObject(o) {
11
+ return typeof o === "object" && !Array.isArray(o) && o !== null;
12
+ }
13
+ function isFunction(o) {
14
+ return typeof o === "function";
15
+ }
4
16
  function percentage(num, total) {
5
17
  if (!num || !total || Number.isNaN(num) || Number.isNaN(total))
6
18
  return 0;
7
19
  return num / total * 100;
8
20
  }
9
21
 
10
- // src/scripts/compare-images-slider.js
11
- function onDrag(element, callback) {
12
- let startX = 0;
13
- let startY = 0;
14
- let endX = 0;
15
- let endY = 0;
22
+ // node_modules/book-of-spells/src/dom.mjs
23
+ function drag(element, opts) {
24
+ if (!element || !(element instanceof Element))
25
+ return;
26
+ if (element.getAttribute("drag-enabled") === "true")
27
+ return;
28
+ let x = 0;
29
+ let y = 0;
30
+ let prevX = 0;
31
+ let prevY = 0;
32
+ let velocityX = 0;
33
+ let velocityY = 0;
16
34
  let dragging = false;
17
- let rect = element.getBoundingClientRect();
35
+ let rect = null;
36
+ let inertiaId = null;
37
+ const options = {
38
+ inertia: false,
39
+ bounce: false,
40
+ friction: 0.9,
41
+ bounceFactor: 0.2,
42
+ callback: null,
43
+ preventDefaultTouch: true
44
+ };
45
+ if (isFunction(opts)) {
46
+ options.callback = opts;
47
+ } else if (isObject(opts)) {
48
+ shallowMerge(options, opts);
49
+ }
50
+ options.friction = Math.abs(options.friction);
51
+ options.bounceFactor = Math.abs(options.bounceFactor);
52
+ element.setAttribute("drag-enabled", "true");
53
+ element.setAttribute("dragging", "false");
54
+ const calcPageRelativeRect = function() {
55
+ const origRect = element.getBoundingClientRect();
56
+ const rect2 = {
57
+ top: origRect.top + window.scrollY,
58
+ left: origRect.left + window.scrollX,
59
+ width: origRect.width,
60
+ height: origRect.height
61
+ };
62
+ return rect2;
63
+ };
64
+ rect = calcPageRelativeRect();
18
65
  const handleStart = function(e) {
19
- const carrier = e.type === "touchstart" ? e.touches[0] : e;
20
- startX = carrier.clientX;
21
- startY = carrier.clientY;
66
+ setXY(e);
22
67
  dragging = true;
23
- rect = element.getBoundingClientRect();
24
- const xPercentage = percentage(startX - rect.left, rect.width);
25
- const yPercentage = percentage(startY - rect.top, rect.height);
26
- const event = new CustomEvent("dragstart", { detail: { target: element, startX, startY, rect, xPercentage, yPercentage } });
68
+ rect = calcPageRelativeRect();
69
+ element.setAttribute("dragging", "true");
70
+ if (inertiaId) {
71
+ cancelAnimationFrame(inertiaId);
72
+ inertiaId = null;
73
+ }
74
+ const event = new CustomEvent("dragstart", { detail: getDetail() });
27
75
  element.dispatchEvent(event);
28
76
  };
29
77
  const handleMove = function(e) {
30
78
  if (!dragging)
31
79
  return;
32
- const carrier = e.type === "touchmove" ? e.touches[0] : e;
33
- endX = carrier.clientX;
34
- endY = carrier.clientY;
35
- handleDragGesture();
80
+ setXY(e);
81
+ velocityX = x - prevX;
82
+ velocityY = y - prevY;
83
+ const detail = getDetail();
84
+ if (options.callback)
85
+ options.callback(detail);
86
+ const event = new CustomEvent("drag", { detail });
87
+ element.dispatchEvent(event);
36
88
  };
37
89
  const handleEnd = function() {
38
90
  dragging = false;
39
- const event = new CustomEvent("dragend", { detail: { target: element, startX, startY, rect, endX, endY } });
91
+ element.setAttribute("dragging", "false");
92
+ if (options.inertia)
93
+ inertiaId = requestAnimationFrame(inertia);
94
+ const event = new CustomEvent("dragend", { detail: getDetail() });
40
95
  element.dispatchEvent(event);
41
96
  };
42
- const handleDragGesture = function() {
43
- const deltaX = endX - startX;
44
- const deltaY = endY - startY;
45
- const left = deltaX < 0;
46
- const up = deltaY < 0;
47
- const xPercentage = percentage(endX - rect.left, rect.width);
48
- const yPercentage = percentage(endY - rect.top, rect.height);
97
+ const setXY = function(e) {
98
+ const carrier = e.touches ? e.touches[0] : e;
99
+ if (e.touches && options.preventDefaultTouch)
100
+ e.preventDefault();
101
+ prevX = x;
102
+ prevY = y;
103
+ x = carrier.pageX;
104
+ y = carrier.pageY;
105
+ };
106
+ const getDetail = function() {
107
+ const relativeX = x - rect.left;
108
+ const relativeY = y - rect.top;
109
+ const xPercentage = percentage(relativeX, rect.width);
110
+ const yPercentage = percentage(relativeY, rect.height);
49
111
  const detail = {
50
112
  target: element,
51
- deltaX,
52
- deltaY,
53
- startX,
54
- startY,
55
- endX,
56
- endY,
57
- horizontalDirection: left ? "left" : "right",
58
- verticalDirection: up ? "up" : "down",
113
+ x,
114
+ y,
115
+ relativeX,
116
+ relativeY,
59
117
  xPercentage,
60
- yPercentage
118
+ yPercentage,
119
+ velocityX,
120
+ velocityY,
121
+ prevX,
122
+ prevY
61
123
  };
62
- if (xPercentage < 0) {
124
+ if (xPercentage < 0)
63
125
  detail.xPercentage = 0;
64
- }
65
- if (xPercentage > 100) {
126
+ if (xPercentage > 100)
66
127
  detail.xPercentage = 100;
67
- }
68
- if (yPercentage < 0) {
128
+ if (yPercentage < 0)
69
129
  detail.yPercentage = 0;
70
- }
71
- if (yPercentage > 100) {
130
+ if (yPercentage > 100)
72
131
  detail.yPercentage = 100;
132
+ return detail;
133
+ };
134
+ const inertia = function() {
135
+ x += velocityX;
136
+ y += velocityY;
137
+ velocityX *= options.friction;
138
+ velocityY *= options.friction;
139
+ if (options.bounce) {
140
+ if (x < rect.left) {
141
+ x = rect.left;
142
+ velocityX *= -options.bounceFactor;
143
+ }
144
+ if (x > rect.width + rect.left) {
145
+ x = rect.width + rect.left;
146
+ velocityX *= -options.bounceFactor;
147
+ }
148
+ if (y < rect.top) {
149
+ y = rect.top;
150
+ velocityY *= -options.bounceFactor;
151
+ }
152
+ if (y > rect.height + rect.top) {
153
+ y = rect.height + rect.top;
154
+ velocityY *= -options.bounceFactor;
155
+ }
73
156
  }
74
- if (callback) {
75
- callback(detail);
157
+ if (Math.abs(velocityX) < 0.1)
158
+ velocityX = 0;
159
+ if (Math.abs(velocityY) < 0.1)
160
+ velocityY = 0;
161
+ const detail = getDetail();
162
+ if (velocityX !== 0 || velocityY !== 0) {
163
+ if (options.callback)
164
+ options.callback(detail);
165
+ const event = new CustomEvent("draginertia", { detail });
166
+ element.dispatchEvent(event);
167
+ inertiaId = requestAnimationFrame(inertia);
168
+ } else {
169
+ inertiaId = null;
170
+ if (options.callback)
171
+ options.callback(detail);
172
+ const event = new CustomEvent("draginertiaend", { detail });
173
+ element.dispatchEvent(event);
76
174
  }
77
- const event = new CustomEvent("drag", { detail });
78
- element.dispatchEvent(event);
79
175
  };
80
176
  element.addEventListener("mousedown", handleStart);
81
177
  element.addEventListener("mousemove", handleMove);
@@ -91,35 +187,100 @@
91
187
  element.removeEventListener("touchstart", handleStart);
92
188
  element.removeEventListener("touchmove", handleMove);
93
189
  element.removeEventListener("touchend", handleEnd);
190
+ if (inertiaId) {
191
+ cancelAnimationFrame(inertiaId);
192
+ inertiaId = null;
193
+ }
94
194
  }
95
195
  };
96
196
  }
197
+
198
+ // src/scripts/compare-images-slider.js
97
199
  var CompareImagesSlider = class {
98
200
  constructor(element, options) {
99
201
  this.element = element;
100
202
  this.frame = this.element.querySelector(".frame");
101
203
  this.second = this.frame.querySelector(":scope > img");
102
204
  this.handle = this.element.querySelector(".handle");
205
+ this.options = {
206
+ inertia: false,
207
+ bounce: false,
208
+ friction: 0.9,
209
+ bounceFactor: 0.1,
210
+ onlyHandle: true,
211
+ vertical: false
212
+ };
213
+ if (options)
214
+ shallowMerge(this.options, options);
215
+ this.checkAndApplyAttribute("vertical");
216
+ if (this.options.vertical && !(this.element.dataset.vertical || this.element.hasAttribute("vertical")))
217
+ this.element.setAttribute("vertical", "");
218
+ if (this.options.onlyHandle)
219
+ this.options.preventDefaultTouch = false;
103
220
  window.addEventListener("resize", () => {
104
221
  requestAnimationFrame(this.setupSecondImage.bind(this));
105
222
  });
106
223
  this.setupSecondImage();
107
- this.drag = onDrag(this.element);
108
- this.element.addEventListener("dragstart", this.updateVisibleHandler.bind(this));
109
- this.element.addEventListener("drag", this.updateVisibleHandler.bind(this));
224
+ this.drag = drag(this.element, this.options);
225
+ this.handleDragBound = false;
226
+ this.boundUpdateVisibleHandler = this.updateVisibleHandler.bind(this);
227
+ const preventDefault = (e) => {
228
+ if (this.handleDragBound)
229
+ e.preventDefault();
230
+ };
231
+ const addEventListeners = () => {
232
+ if (this.handleDragBound)
233
+ return;
234
+ this.handleDragBound = true;
235
+ this.element.addEventListener("dragstart", this.boundUpdateVisibleHandler);
236
+ this.element.addEventListener("drag", this.boundUpdateVisibleHandler);
237
+ this.element.addEventListener("draginertia", this.boundUpdateVisibleHandler);
238
+ this.element.addEventListener("draginertiaend", () => {
239
+ this.element.removeEventListener("draginertia", this.boundUpdateVisibleHandler);
240
+ });
241
+ this.element.addEventListener("touchstart", preventDefault);
242
+ };
243
+ const removeEventListeners = () => {
244
+ if (!this.handleDragBound)
245
+ return;
246
+ this.handleDragBound = false;
247
+ this.element.removeEventListener("dragstart", this.boundUpdateVisibleHandler);
248
+ this.element.removeEventListener("drag", this.boundUpdateVisibleHandler);
249
+ this.element.removeEventListener("touchstart", preventDefault);
250
+ };
251
+ if (this.options.onlyHandle) {
252
+ this.handle.addEventListener("mousedown", addEventListeners);
253
+ this.handle.addEventListener("touchstart", addEventListeners);
254
+ document.addEventListener("mouseup", removeEventListeners);
255
+ document.addEventListener("touchend", removeEventListeners);
256
+ } else {
257
+ this.element.addEventListener("dragstart", this.boundUpdateVisibleHandler);
258
+ this.element.addEventListener("drag", this.boundUpdateVisibleHandler);
259
+ this.element.addEventListener("draginertia", this.boundUpdateVisibleHandler);
260
+ }
261
+ }
262
+ checkAndApplyAttribute(attribute) {
263
+ if (this.element.dataset[attribute] || this.element.hasAttribute(attribute))
264
+ this.options[attribute] = true;
110
265
  }
111
266
  setupSecondImage() {
112
267
  const width = this.element.offsetWidth + "px";
113
268
  this.second.style.width = width;
114
269
  }
115
270
  updateVisibleHandler(e) {
271
+ if (this.options.vertical) {
272
+ this.frame.style.height = e.detail.yPercentage + "%";
273
+ this.handle.style.top = e.detail.yPercentage + "%";
274
+ return;
275
+ }
116
276
  this.frame.style.width = e.detail.xPercentage + "%";
117
277
  this.handle.style.left = e.detail.xPercentage + "%";
118
278
  }
119
279
  destroy() {
120
280
  this.drag.destroy();
121
- this.element.removeEventListener("dragstart", this.updateVisibleHandler.bind(this));
122
- this.element.removeEventListener("drag", this.updateVisibleHandler.bind(this));
281
+ this.element.removeEventListener("dragstart", this.boundUpdateVisibleHandler);
282
+ this.element.removeEventListener("drag", this.boundUpdateVisibleHandler);
283
+ this.element.removeEventListener("draginertia", this.boundUpdateVisibleHandler);
123
284
  }
124
285
  };
125
286