Я пытаюсь изменить код Javascript, который является плагином галереи. Я добавил кнопку для модели начальной загрузки на главном экране Item. Когда я нажимаю на нее, модель открывается, но окно контента закрывается, как это определено в плагине. Я хочу, чтобы держать открытым раздел содержимого и отключить указатель мыши стиль кросс при наведении модальной кнопки. Рабочая демоверсия здесь.
http://216.244.79.226/testGrid/
Я пробовал event.stopPropagation ();и другие коды, но ничего не работает. Любой, пожалуйста, помогите.
Plugin code
-------------------------------------------------------------------
{
const MathUtils = {
lineEq: (y2, y1, x2, x1, currentVal) => {
// y = mx + b
var m = (y2 - y1) / (x2 - x1), b = y1 - m * x1;
return m * currentVal + b;
},
lerp: (a, b, n) => (1 - n) * a + n * b
};
// Window size
let winsize;
const calcWinsize = () => winsize = {width: window.innerWidth, height: window.innerHeight};
calcWinsize();
window.addEventListener('resize', calcWinsize);
const getMousePos = (ev) => {
let posx = 0;
let posy = 0;
if (!ev) ev = window.event;
if (ev.pageX || ev.pageY) {
posx = ev.pageX;
posy = ev.pageY;
}
else if (ev.clientX || ev.clientY) {
posx = ev.clientX + body.scrollLeft + docEl.scrollLeft;
posy = ev.clientY + body.scrollTop + docEl.scrollTop;
}
return {x: posx, y: posy};
}
// Track the mouse position
let mousePos = {x: winsize.width/2, y: winsize.height/2};
window.addEventListener('mousemove', ev => mousePos = getMousePos(ev));
// Custom mouse cursor.
class CursorFx {
constructor(el) {
this.DOM = {el: el};
this.DOM.toggle = this.DOM.el.querySelector('.cursor__inner--circle');
this.DOM.title = this.DOM.el.querySelector('.cursor__inner--text');
this.bounds = {
toggle: this.DOM.toggle.getBoundingClientRect(),
title: this.DOM.title.getBoundingClientRect()
};
this.lastMousePos = {
toggle: {x: mousePos.x - this.bounds.toggle.width/2, y: mousePos.y - this.bounds.toggle.height/2},
title: {x: mousePos.x - this.bounds.title.width/2, y: mousePos.y - this.bounds.title.height/2}
};
this.lastScale = 1;
this.lastOpacity = 1;
requestAnimationFrame(() => this.render());
}
render() {
// Mouse movement distance on the x-axis
const diff = this.lastMousePos.toggle.x - (mousePos.x - this.bounds.toggle.width/2);
// Check if mouse is on the right side of the viewport
const rightSide = mousePos.x >= winsize.width/2;
// Switch the side of the title element
this.DOM.title.style.left = rightSide ? 'auto' : '30px';
this.DOM.title.style.right = rightSide ? '30px' : 'auto';
// The position of the title/toggle and the viewport side will determine the speed for both of these elements
const lerpFactor = {
toggle: rightSide ? diff < 0 ? 0.15 : 0.1 : diff < 0 ? 0.1 : 0.15,
title: rightSide ? diff < 0 ? 0.1 : 0.15 : diff < 0 ? 0.15 : 0.1
};
// Update the mouse position values given the previous calculated lerp value
this.lastMousePos.toggle.x = MathUtils.lerp(this.lastMousePos.toggle.x, mousePos.x - this.bounds.toggle.width/2, lerpFactor.toggle);
this.lastMousePos.toggle.y = MathUtils.lerp(this.lastMousePos.toggle.y, mousePos.y - this.bounds.toggle.height/2, lerpFactor.toggle);
this.lastMousePos.title.x = MathUtils.lerp(this.lastMousePos.title.x, mousePos.x - this.bounds.title.width/2, lerpFactor.title);
this.lastMousePos.title.y = MathUtils.lerp(this.lastMousePos.title.y, mousePos.y - this.bounds.title.height/2, lerpFactor.title);
// Also the scale and opacity values for the toggle
this.lastScale = MathUtils.lerp(this.lastScale, 1, 0.15);
this.lastOpacity = MathUtils.lerp(this.lastOpacity, 1, 0.1);
// Apply the styles
this.DOM.toggle.style.transform = `translateX(${(this.lastMousePos.toggle.x)}px) translateY(${this.lastMousePos.toggle.y}px) scale(${this.lastScale})`;
this.DOM.toggle.style.opacity = this.lastOpacity;
this.DOM.title.style.transform = `translateX(${(this.lastMousePos.title.x)}px) translateY(${this.lastMousePos.title.y}px)`;
requestAnimationFrame(() => this.render());
}
setTitle(title) {
// Sets the title content
this.DOM.title.innerHTML = title;
}
click() {
// Scales down and fades out the mouse toggle
this.lastScale = .5;
this.lastOpacity = 0;
}
toggle() {
const isCircle = this.DOM.toggle.classList.contains('cursor__inner--circle');
this.DOM.toggle.classList[isCircle ? 'remove' : 'add']('cursor__inner--circle');
this.DOM.toggle.classList[isCircle ? 'add' : 'remove']('cursor__inner--cross');
this.DOM.title.style.opacity = isCircle ? 0 : 1;
}
}
const cursor = new CursorFx(document.querySelector('.cursor'));
//const modalBtn = document.querySelector('#videoBtn');
class Grid {
constructor(el) {
this.DOM = {el: el};
// The grid element
this.DOM.grid = this.DOM.el.querySelector('.grid');
// Thr grid items
this.DOM.items = [...this.DOM.grid.children];
// totla number of grid items
this.itemsTotal = this.DOM.items.length;
// The content element ("behind" the grid)
this.DOM.content = document.querySelector('.content');
this.DOM.contentVideo = document.querySelector('.content-video');
this.DOM.modalBtn = document.querySelector('#videoBtn');
this.DOM.contentTitle = this.DOM.content.querySelector('.content__title');
// Calculate heights of both the grid wrap and the grid, and also:
// . the difference between them (then used for the grid/mousemove translation)
// . the number of rows/columns
this.calculateSize();
// The grid will be initially translated so it is in the center
this.gridTranslation = {x: 0, y: -1*this.extraHeight/2};
// Linear interpolation easing percentage (for the grid movement on mouse move)
this.lerpFactor = 0.04;
this.initEvents();
requestAnimationFrame(() => this.render());
}
calculateSize() {
// The height of the grid wrap
this.height = this.DOM.el.offsetHeight;
// The difference between the height of the grid wrap and the height of the grid. This is the amount we can translate the grid
this.extraHeight = this.DOM.grid.offsetHeight - this.height;
// Number of grid columns. The CSS variable --cell-number gives us the number of rows
this.columns = this.itemsTotal/getComputedStyle(this.DOM.grid).getPropertyValue('--cell-number');
// The animejs stagger function needs an array [cols,rows]
this.gridDef = [this.columns, this.itemsTotal/this.columns];
}
initEvents() {
// Window resize event
// The lerpFactor will change to 1 so theres no delay when translating the grid (or we would see the gaps on the top and bottom)
window.addEventListener('resize', () => {
this.lerpFactor = 1;
// Recalculate..
this.calculateSize();
this.columns = this.itemsTotal/getComputedStyle(this.DOM.grid).getPropertyValue('--cell-number');
clearTimeout(this.resizeTimer);
this.resizeTimer = setTimeout(() => this.lerpFactor = 0.04, 250);
});
this.DOM.items.forEach((item, pos) => {
// The item's title.
const title = item.dataset.title;
// Show the title next to the cursor.
item.addEventListener('mouseenter', () => cursor.setTitle(title));
item.addEventListener('click', () => {
// Position of the clicked item
this.pos = pos;
this.title = title;
// Start the effect and show the content behind
this.showContent();
// Force to show the title next to the cursor (it might not update because of the grid animation - the item under the mouse can be a different one than the one the user moved the mouse to)
cursor.setTitle(title);
});
});
// Show back the grid.
this.DOM.content.addEventListener('click', () => this.showGrid());
}
// This is where the main grid effect takes place
// Animates the boxes out and reveals the content "behind"
showContent() {
if ( this.isAnimating ) {
return false;
}
this.isAnimating = true;
// Set the content background image and title
this.DOM.content.style.backgroundImage = this.DOM.items[this.pos].querySelector('.grid__item-inner').style.backgroundImage.replace(/img/g, 'img/large');
//this.DOM.contentVideo.setAttribute.src = this.DOM.items[this.pos].querySelector('.grid__item-inner').setAttribute('src', /img/g, 'img/video');
this.DOM.contentVideo.src = this.DOM.items[this.pos].querySelector('.grid__item-inner').dataset.title.replace(/img/g, 'img');
this.DOM.contentTitle.innerHTML = this.title;
//this.DOM.content.modalBtn = return false;
// Scales down and fades out the mouse toggle
cursor.click();
cursor.toggle();
this.animation = anime({
targets: this.DOM.items,
duration: 20,
easing: 'easeOutQuad',
opacity: 0,
delay: anime.stagger(70, {grid: this.gridDef, from: this.pos})
});
this.animation.finished.then(() => {
// Pointer events class
this.DOM.el.classList.add('grid-wrap--hidden');
this.isAnimating = false;
});
// Animates the title
anime({
targets: this.DOM.contentTitle,
duration: 1700,
delay: 200,
easing: 'easeOutExpo',
opacity: [0,1],
translateY: [50,0]
});
console.log('Function 1');
}
showGrid() {
if ( this.isAnimating ) {
return false;
}
this.isAnimating = true;
cursor.click();
cursor.toggle();
this.DOM.el.classList.remove('grid-wrap--hidden');
// Could have used the reverse() but there seems to be a bug (glitch)..
this.animation = anime({
targets: this.DOM.items,
duration: 20,
easing: 'easeOutQuad',
opacity: [0,1],
delay: anime.stagger(70, {grid: this.gridDef, from: this.pos, direction: 'reverse'})
});
this.animation.finished.then(() => this.isAnimating = false);
console.log('Function 2');
}
// Translate the grid when moving the mouse
render() {
// The translation will be either 0 or -1*this.extraHeight depending on the position of the mouse on the y-axis
this.gridTranslation.y = MathUtils.lerp(this.gridTranslation.y, Math.min(Math.max(MathUtils.lineEq(-1*this.extraHeight, 0, this.height-this.height*.1, this.height*.1, mousePos.y), -1*this.extraHeight),0), this.lerpFactor);
this.DOM.grid.style.transform = `translateY(${this.gridTranslation.y}px)`;
requestAnimationFrame(() => this.render());
}
}
// Initialize the grid
new Grid(document.querySelector('.grid-wrap'));
// Preload all the images in the page
imagesLoaded(document.querySelectorAll('.grid__item-inner, img'), {background: true}, () => document.body.classList.remove('loading'));
}
HTML code
-------------------------------------------------------------------
<body class="demo-1 loading">
<!-- we are "preloading" the images in this hard-coded way; this should be done properly in a project, i.e. on click load -->
<div class="hidden">
<img src="img/large/1.jpg"/>
<img src="img/large/2.jpg"/>
<img src="img/large/3.jpg"/>
<img src="img/large/4.jpg"/>
<img src="img/large/5.jpg"/>
<img src="img/large/6.jpg"/>
<img src="img/large/7.jpg"/>
<img src="img/large/8.jpg"/>
<img src="img/large/9.jpg"/>
<img src="img/large/10.jpg"/>
<img src="img/large/11.jpg"/>
<img src="img/large/12.jpg"/>
<img src="img/large/13.jpg"/>
<img src="img/large/14.jpg"/>
<img src="img/large/15.jpg"/>
<img src="img/large/16.jpg"/>
<img src="img/large/17.jpg"/>
<img src="img/large/18.jpg"/>
<img src="img/large/19.jpg"/>
<img src="img/large/20.jpg"/>
<img src="img/large/21.jpg"/>
</div>
<main>
<div class="content">
<div class="container" id="videoCont">
<div class="row">
<div class="col-12 text-center">
<h2 class="content__title">Yerevan</h2>
<button type="button" id="videoBtn" class="btn btn-primary" data-toggle="modal" data-target="#videoModal">
Launch demo modal
</button>
</div>
</div>
</div>
<div class="modal fade" id="videoModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<video class="content-video" width="320" height="240" controls>
<source src="" type="video/mp4">
</video>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
<div class="grid-wrap">
<div class="grid">
<div class="grid__item" data-title="London"><div class="grid__item-inner" data-title="img/video/video1.mp4" style="background-image:url(img/1.jpg)"></div></div>
<div class="grid__item" data-title="Yerevan"><div class="grid__item-inner" data-title="img/video/video2.mp4" style="background-image:url(img/2.jpg)"></div></div>
<div class="grid__item" data-title="Paris"><div class="grid__item-inner" data-title="img/video/video3.mp4" style="background-image:url(img/3.jpg)"></div></div>
<div class="grid__item" data-title="Madrid"><div class="grid__item-inner" data-title="img/video/video4.mp4" style="background-image:url(img/4.jpg)"></div></div>
<div class="grid__item" data-title="Moscow"><div class="grid__item-inner" data-title="img/video/video5.mp4" style="background-image:url(img/5.jpg)"></div></div>
<div class="grid__item" data-title="Lagos"><div class="grid__item-inner" data-title="img/video/video6.mp4" style="background-image:url(img/6.jpg)"></div></div>
<div class="grid__item" data-title="Dublin"><div class="grid__item-inner" data-title="img/video/video7.mp4" style="background-image:url(img/7.jpg)"></div></div>
<div class="grid__item" data-title="Bangkok"><div class="grid__item-inner" data-title="img/video/video8.mp4" style="background-image:url(img/8.jpg)"></div></div>
<div class="grid__item" data-title="Luanda"><div class="grid__item-inner" data-title="img/video/video9.mp4" style="background-image:url(img/9.jpg)"></div></div>
<div class="grid__item" data-title="Buenos Aires"><div class="grid__item-inner" data-title="img/video/video10.mp4" style="background-image:url(img/10.jpg)"></div></div>
<div class="grid__item" data-title="Berlin"><div class="grid__item-inner" data-title="img/video/video11.mp4" style="background-image:url(img/11.jpg)"></div></div>
<div class="grid__item" data-title="Vienna"><div class="grid__item-inner" data-title="img/video/video12.mp4" style="background-image:url(img/12.jpg)"></div></div>
<div class="grid__item" data-title="Minsk"><div class="grid__item-inner" data-title="img/video/video13.mp4" style="background-image:url(img/13.jpg)"></div></div>
<div class="grid__item" data-title="Brussels"><div class="grid__item-inner" data-title="img/video/video14.mp4" style="background-image:url(img/14.jpg)"></div></div>
<div class="grid__item" data-title="Lisbon"><div class="grid__item-inner" data-title="img/video/video15.mp4" style="background-image:url(img/15.jpg)"></div></div>
<div class="grid__item" data-title="Porto-Novo"><div class="grid__item-inner" data-title="img/video/video16.mp4" style="background-image:url(img/16.jpg)"></div></div>
<div class="grid__item" data-title="Sofia"><div class="grid__item-inner" data-title="img/video/video17.mp4" style="background-image:url(img/17.jpg)"></div></div>
<div class="grid__item" data-title="Phnom Penh"><div class="grid__item-inner" data-title="img/video/video18.mp4" style="background-image:url(img/18.jpg)"></div></div>
<div class="grid__item" data-title="Ottawa"><div class="grid__item-inner" data-title="img/video/video19.mp4" style="background-image:url(img/19.jpg)"></div></div>
<div class="grid__item" data-title="Praia"><div class="grid__item-inner" data-title="img/video/video20.mp4" style="background-image:url(img/20.jpg)"></div></div>
<div class="grid__item" data-title="Bogota"><div class="grid__item-inner" data-title="img/video/video21.mp4" style="background-image:url(img/21.jpg)"></div></div>
</div>
</div>
</main>
<div class="cursor">
<div class="cursor__inner cursor__inner--circle"></div>
<span class="cursor__inner cursor__inner--text"> </span>
</div>
<script src="js/imagesloaded.pkgd.min.js"></script>
<script src="js/anime.min.js"></script>
<script src="js/jquery-2.2.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/demo1.js"></script>
</body>