166 lines
4.3 KiB
JavaScript
166 lines
4.3 KiB
JavaScript
|
import $ from 'jquery';
|
||
|
|
||
|
const $wnd = $(window);
|
||
|
|
||
|
/**
|
||
|
* Check if lines cross
|
||
|
*
|
||
|
* @param {Object} a - first point of the first line
|
||
|
* @param {Object} b - second point of the first line
|
||
|
* @param {Object} c - first point of the second line
|
||
|
* @param {Object} d - second point of the second line
|
||
|
*
|
||
|
* @return {boolean} cross lines
|
||
|
*/
|
||
|
function isCrossLine(a, b, c, d) {
|
||
|
// Working code #1:
|
||
|
//
|
||
|
// var common = (b.x - a.x)*(d.y - c.y) - (b.y - a.y)*(d.x - c.x);
|
||
|
// if (common === 0) {
|
||
|
// return false;
|
||
|
// }
|
||
|
//
|
||
|
// var rH = (a.y - c.y)*(d.x - c.x) - (a.x - c.x)*(d.y - c.y);
|
||
|
// var sH = (a.y - c.y)*(b.x - a.x) - (a.x - c.x)*(b.y - a.y);
|
||
|
//
|
||
|
// var r = rH / common;
|
||
|
// var s = sH / common;
|
||
|
//
|
||
|
// return r >= 0 && r <= 1 && s >= 0 && s <= 1;
|
||
|
|
||
|
// Working code #2:
|
||
|
const v1 = (d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x);
|
||
|
const v2 = (d.x - c.x) * (b.y - c.y) - (d.y - c.y) * (b.x - c.x);
|
||
|
const v3 = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
||
|
const v4 = (b.x - a.x) * (d.y - a.y) - (b.y - a.y) * (d.x - a.x);
|
||
|
return v1 * v2 <= 0 && v3 * v4 <= 0;
|
||
|
}
|
||
|
|
||
|
// Init Events.
|
||
|
$(document).on('initEvents.vpf', (event, self) => {
|
||
|
if (event.namespace !== 'vpf' || self.options.itemsStyle !== 'fly') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const evp = `.vpf-uid-${self.uid}`;
|
||
|
|
||
|
// determine cursor position
|
||
|
let lastCursorPos = {};
|
||
|
$wnd.on(`mousemove${evp}`, (e) => {
|
||
|
lastCursorPos = {
|
||
|
x: e.clientX,
|
||
|
y: e.clientY,
|
||
|
};
|
||
|
});
|
||
|
|
||
|
self.$item.on(
|
||
|
`mouseenter${evp} mouseleave${evp}`,
|
||
|
'.vp-portfolio__item',
|
||
|
function (e) {
|
||
|
const $this = $(this);
|
||
|
const itemRect = $this[0].getBoundingClientRect();
|
||
|
const $overlay = $this.find('.vp-portfolio__item-overlay');
|
||
|
const enter = e.type === 'mouseenter';
|
||
|
let endX = '0%';
|
||
|
let endY = '0%';
|
||
|
const curCursorPos = {
|
||
|
x: e.clientX,
|
||
|
y: e.clientY,
|
||
|
};
|
||
|
|
||
|
// find the corner that placed on cursor path.
|
||
|
let isUp = isCrossLine(
|
||
|
{ x: itemRect.left, y: itemRect.top },
|
||
|
{ x: itemRect.left + itemRect.width, y: itemRect.top },
|
||
|
curCursorPos,
|
||
|
lastCursorPos
|
||
|
);
|
||
|
let isDown = isCrossLine(
|
||
|
{ x: itemRect.left, y: itemRect.top + itemRect.height },
|
||
|
{
|
||
|
x: itemRect.left + itemRect.width,
|
||
|
y: itemRect.top + itemRect.height,
|
||
|
},
|
||
|
curCursorPos,
|
||
|
lastCursorPos
|
||
|
);
|
||
|
let isLeft = isCrossLine(
|
||
|
{ x: itemRect.left, y: itemRect.top },
|
||
|
{ x: itemRect.left, y: itemRect.top + itemRect.height },
|
||
|
curCursorPos,
|
||
|
lastCursorPos
|
||
|
);
|
||
|
let isRight = isCrossLine(
|
||
|
{ x: itemRect.left + itemRect.width, y: itemRect.top },
|
||
|
{
|
||
|
x: itemRect.left + itemRect.width,
|
||
|
y: itemRect.top + itemRect.height,
|
||
|
},
|
||
|
curCursorPos,
|
||
|
lastCursorPos
|
||
|
);
|
||
|
|
||
|
// Sometimes isCrossLine returned false, so we need to check direction manually (less accurate, but it is not a big problem).
|
||
|
if (!isUp && !isDown && !isLeft && !isRight) {
|
||
|
const x =
|
||
|
(itemRect.width / 2 - curCursorPos.x + itemRect.left) /
|
||
|
(itemRect.width / 2);
|
||
|
const y =
|
||
|
(itemRect.height / 2 - curCursorPos.y + itemRect.top) /
|
||
|
(itemRect.height / 2);
|
||
|
if (Math.abs(x) > Math.abs(y)) {
|
||
|
if (x > 0) {
|
||
|
isLeft = true;
|
||
|
} else {
|
||
|
isRight = true;
|
||
|
}
|
||
|
} else if (y > 0) {
|
||
|
isUp = true;
|
||
|
} else {
|
||
|
isDown = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isUp) {
|
||
|
endY = '-100.1%';
|
||
|
} else if (isDown) {
|
||
|
endY = '100.1%';
|
||
|
} else if (isLeft) {
|
||
|
endX = '-100.1%';
|
||
|
} else if (isRight) {
|
||
|
endX = '100.1%';
|
||
|
}
|
||
|
|
||
|
if (enter) {
|
||
|
$overlay.css({
|
||
|
transition: 'none',
|
||
|
transform: `translateX(${endX}) translateY(${endY}) translateZ(0)`,
|
||
|
});
|
||
|
// Trigger a reflow, flushing the CSS changes. This need to fix some glithes in Safari and Firefox.
|
||
|
// Info here - https://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily
|
||
|
// eslint-disable-next-line no-unused-expressions
|
||
|
$overlay[0].offsetHeight;
|
||
|
}
|
||
|
|
||
|
$overlay.css({
|
||
|
transition: '.2s transform ease-in-out',
|
||
|
transform: `translateX(${enter ? '0%' : endX}) translateY(${
|
||
|
enter ? '0%' : endY
|
||
|
}) translateZ(0)`,
|
||
|
});
|
||
|
}
|
||
|
);
|
||
|
});
|
||
|
|
||
|
// Destroy Events.
|
||
|
$(document).on('destroyEvents.vpf', (event, self) => {
|
||
|
if (event.namespace !== 'vpf' || self.options.itemsStyle !== 'fly') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const evp = `.vpf-uid-${self.uid}`;
|
||
|
|
||
|
$wnd.off(`mousemove${evp}`);
|
||
|
self.$item.off(`mouseenter${evp} mouseleave${evp}`);
|
||
|
});
|