-
Notifications
You must be signed in to change notification settings - Fork 52
/
zoomOnHover.js
103 lines (101 loc) · 3.65 KB
/
zoomOnHover.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// this component displays an image with the width of the parent element and on hover shows
// the full image or a scaled image in the image area.
// features: activate/deactivate method, active/inactive on load, scale parameter, separate zoom image,
// event when all images loaded, event when images resized (responsive css, etc)
function pageOffset(el) {
// -> {x: number, y: number}
// get the left and top offset of a dom block element
var rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return {
y: rect.top + scrollTop,
x: rect.left + scrollLeft
}
}
var zoomOnHover = {
props: ["imgNormal", "imgZoom", "scale", "disabled"],
template: `<div class="zoom-on-hover" v-bind:class="{zoomed}" @touchstart="touchzoom"
@mousemove="move" @mouseenter="zoom" @mouseleave="unzoom">
<img class="normal" ref="normal" :src="imgNormal"/>
<img class="zoom" ref="zoom" :src="imgZoom || imgNormal"/></div>`,
data: function() {
return {
scaleFactor: 1,
resizeCheckInterval: null,
zoomed: false
}
},
methods: {
touchzoom: function(event) {
if (this.disabled) return
this.move(event)
this.zoomed = !this.zoomed
},
zoom: function() {
if (!this.disabled) this.zoomed = true
},
unzoom: function() {
if (!this.disabled) this.zoomed = false
},
move: function(event) {
if (this.disabled || !this.zoomed) return
var offset = pageOffset(this.$el)
var zoom = this.$refs.zoom
var normal = this.$refs.normal
var relativeX = event.clientX - offset.x + window.pageXOffset
var relativeY = event.clientY - offset.y + window.pageYOffset
var normalFactorX = relativeX / normal.offsetWidth
var normalFactorY = relativeY / normal.offsetHeight
var x = normalFactorX * (zoom.offsetWidth * this.scaleFactor - normal.offsetWidth)
var y = normalFactorY * (zoom.offsetHeight * this.scaleFactor - normal.offsetHeight)
zoom.style.left = -x + "px"
zoom.style.top = -y + "px"
},
initEventLoaded: function() {
// emit the "loaded" event if all images have been loaded
var promises = [this.$refs.zoom, this.$refs.normal].map(function(image) {
return new Promise(function(resolve, reject) {
image.addEventListener("load", resolve)
image.addEventListener("error", reject)
})
})
var component = this
Promise.all(promises).then(function() {
component.$emit("loaded")
})
},
initEventResized: function() {
var normal = this.$refs.normal
var previousWidth = normal.offsetWidth
var previousHeight = normal.offsetHeight
var component = this
this.resizeCheckInterval = setInterval(function() {
if ((previousWidth != normal.offsetWidth) || (previousHeight != normal.offsetHeight)) {
previousWidth = normal.offsetWidth
previousHeight = normal.offsetHeight
component.$emit("resized", {
width: normal.width,
height: normal.height,
fullWidth: normal.naturalWidth,
fullHeight: normal.naturalHeight
})
}
}, 1000)
}
},
mounted: function() {
if (this.$props.scale) {
this.scaleFactor = parseInt(this.$props.scale)
this.$refs.zoom.style.transform = "scale(" + this.scaleFactor + ")"
}
this.initEventLoaded()
this.initEventResized()
},
updated: function() {
this.initEventLoaded()
},
beforeDestroy: function() {
this.resizeCheckInterval && clearInterval(this.resizeCheckInterval)
}
}