How to determine why a hyperlink is not working? - javascript

I've created a new format of the main banner for my page. However, all the links except for the little preview picture on the right side isn't working and I have no idea why.
I'm a designer who's trying to do publishing at the same time so my knowledge for js is very limited but I deal with css and html quite well.
Here is the link
;
(function($) {
$.fn.DB_tabArrowSlideMove2 = function(options) {
var opt = {
motionType: 'fade',
motionSpeed: 300,
autoRollingTime: 3000,
videoRollingTime: 6000,
arrowVisible: true,
overRolling: false,
random: false,
yt_player: []
};
$.extend(opt, options);
return this.each(function() {
var $this = $(this);
var $img = $this.find('.img');
var $img_li = $img.find('> li');
var $arrow = $this.find('.arrow');
var $next = $this.find('.next');
var $prev = $this.find('.prev');
var $auto = $this.find('.auto');
var len = $img_li.length;
//console.log(len);
var $btn = $this.find('.btn');
if (len == 1) {
$next.hide();
$prev.hide();
$btn.hide();
return;
}
if ($btn.find('li').length == 0) {
for (var i = 0; i < len; i++) {
$btn.append('<li class=n' + (i + 1) + '><span>' + (i + 1) + '</span></li>');
};
};
var $btn_li = $btn.find('> li');
var current = 0;
var oldCurrent = 0;
var dir = 'next';
var random = opt.random;
if (random) {
current = Math.floor(Math.random() * len);
oldCurrent = current;
dir = 'random';
};
var timerId = 0;
var timer = 0;
var autoPlay = true;
var arrowOver = false;
var imgWidth = $img_li.width();
var imgHeight = $img_li.height();
var overRolling = opt.overRolling;
var arrowVisible = opt.arrowVisible;
var motionType = opt.motionType;
var motionSpeed = opt.motionSpeed;
var autoRollingTime = opt.autoRollingTime;
var videoRollingTime = opt.videoRollingTime;
var mOver = false;
//
var $window = $(window);
//var yt_player=opt.yt_player;
var yt_length = yt_player.length;
var yt_pos = {};
var scrollTop = 0;
if (yt_length) {
//var $iframe=$this.find('iframe');
$iframe.each(function(index) {
$(this).attr('data-no', index);
});
$window.scroll(function() {
videoSoundByWinScroll();
});
var isMute = 1;
videoSoundByWinScroll();
function videoSoundByWinScroll() {
yt_pos.start = $this.offset().top;
yt_pos.height = $this.height()
yt_pos.end = yt_pos.start + yt_pos.height
scrollTop = $(this).scrollTop();
if (scrollTop + $window.height() > yt_pos.start && scrollTop < yt_pos.end) {
if (isMute == 0) {
var _iframe = $img_li.eq(current).find('iframe');
if (_iframe.length) {
var _no = _iframe.attr('data-no') * 1;
yt_player[_no].playVideo();
}
isMute = 1;
$this.mouseleave();
}
} else {
if (isMute == 1) {
for (var i = 0; i < yt_length; i++) {
//console.log('멈춤');
yt_player[i].pauseVideo();
}
isMute = 0;
$this.mouseenter();
}
}
}
}
init();
function init() {
setCss();
setMouseEvent();
setEnterFrame();
};
function setCss() {
if (arrowVisible == false) {
$arrow.hide();
$auto.hide();
};
for (var i = 0; i < len; i++) {
var _img = $img_li.eq(i);
switch (motionType) {
case 'x':
if (i == current) {
_img.css({
'left': 0,
'top': 0
});
} else {
_img.css({
'left': imgWidth * i,
'top': 0
});
}
break;
case 'y':
if (i == current) {
_img.css({
'top': 0,
'left': 0
});
} else {
_img.css({
'top': imgHeight * i,
'left': 0
});
}
break;
default:
_img.css({
'top': 0,
'left': 0
});
if (i == current) {
_img.show();
} else {
_img.hide();
};
};
};
$btn_li.removeClass('on');
$btn_li.eq(current).addClass('on');
$btn_li.find('span').stop().css('width', 0);
function setMouseEvent() {
$this.bind('mouseenter', function() {
mOver = true;
if (overRolling == false && autoPlay == true) {
$btn_li.eq(current).find('span').stop();
};
if (arrowVisible == false) {
$arrow.show();
$auto.show();
};
});
$this.bind('mouseleave', function() {
mOver = false;
if (overRolling == false && autoPlay == true) {
var time
if ($img_li.eq(current).find('iframe').length) {
time = videoRollingTime - videoRollingTime * $btn_li.eq(current).find('span').width() / $btn_li.eq(current).find('span').parent().width();
} else {
time = autoRollingTime - autoRollingTime * $btn_li.eq(current).find('span').width() / $btn_li.eq(current).find('span').parent().width();
}
//console.log('남은시간:'+time);
$btn_li.eq(current).find('span').animate({
'width': '100%'
}, time, 'linear');
};
if (arrowVisible == false) {
$arrow.hide();
$auto.hide();
};
if (random && (motionType != 'x' || motionType != 'y')) {
dir = 'random';
}
});
$btn_li.bind('mouseenter', function() {
var _index = $(this).index();
if (_index > current) {
//dir='next';
} else {
//dir='prev';
};
if (current != _index) {
current = _index;
setAnimation();
};
});
$arrow.bind('mouseenter', function() {
arrowOver = true;
});
$arrow.bind('mouseleave', function() {
arrowOver = false;
});
$next.bind('click', function() {
dir = 'next';
changeCurrent();
});
$prev.bind('click', function() {
dir = 'prev';
changeCurrent();
});
$auto.bind('click', function() {
if (autoPlay) {
autoPlay = false;
setReplace($auto.find('img'), 'src', '_on', '_off');
} else {
autoPlay = true;
setReplace($auto.find('img'), 'src', '_off', '_on');
};
});
};
function changeCurrent() {
if (autoPlay || arrowOver) {
if (dir == 'next') {
current++;
if (current == len) {
current = 0
}
} else if (dir == 'prev') {
current--;
if (current < 0) {
current = len - 1;
}
dir = "next";
} else {
for (var i = 0; i < 10; i++) {
current = Math.floor(Math.random() * len);
if (oldCurrent != current) {
break;
}
}
}
//console.log(current);
setAnimation();
};
};
function setEnterFrame() {
var rollingTime = 0;
if (autoRollingTime > 0) {
setInterval(function() {
// console.log(mOver,current,dir)
if (mOver == false || overRolling == true) {
timer++;
//console.log('현재동작중인:'+current)
//video
if ($img_li.eq(current).find('iframe').length) {
rollingTime = videoRollingTime;
} else {
rollingTime = autoRollingTime;
}
if (timer % (Math.ceil(rollingTime / 100)) == 0) {
changeCurrent();
}
}
}, 100);
};
};
$btn_li.removeClass('on');
$btn_li.eq(current).addClass('on');
$btn_li.find('span').stop().css('width', 0);
if (mOver == false || overRolling == true) {
function setReplace(_mc, _attr, _old, _new) {
var str = _mc.attr(_attr);
if (String(str).search(_old) != -1) {
_mc.attr(_attr, str.replace(_old, _new));
};
};
});
};
})(jQuery);
if ($iframe.length == 0) {
$('.JS_mainBnr').DB_tabArrowSlideMove2({
motionType: 'fade',
motionSpeed: 600,
autoRollingTime: 6000,
arrowVisible: true,
overRolling: false,
random: false
})
}
.JS_mainBnr {
margin-top: -283px;
z-index: 1;
width: 100%;
height: 369px/;
overflow: hidden;
margin: 0 auto;
text-align: center
}
.JS_mainBnr .img {
position: relative;
margin: 0 auto;
width: auto;
height: 100%;
}
.JS_mainBnr .img:after {
content: "";
display: block;
clear: both;
}
.JS_mainBnr .img li {
position: absolute;
top: 0;
left: 50%!important;
width: 5000px;
height: auto;
margin-left: -2500px;
text-align: center;
}
.JS_mainBnr .img li a {
width: 5000px;
height: auto;
display: inline-block
}
.JS_mainBnr .img li:first-child {
z-index: 1;
}
/* Button */
.JS_mainBnr .btn {
z-index: 3;
position: absolute;
top: 0px;
letter-spacing: -4px;
top: 0;
left: 50%!important;
width: 5000px;
height: 100%;
margin-left: -2630px;
text-align: center;
}
.JS_mainBnr .btn:after {
content: "";
display: block;
clear: both;
}
.JS_mainBnr .btn li {
position: relative;
*zoom: 1;
padding: 0 0;
background: rgba(255, 255, 255, .5);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.10);
color: #333;
font-size: 12px;
cursor: pointer;
letter-spacing: 0;
transition: all .2s ease;
-webkit-transition: all .2s ease;
width: 257px;
margin-left: 60%;
}
.JS_mainBnr:hover .btn li {
background: rgba(0, 0, 0, .1);
}
.JS_mainBnr:hover .btn li img {
opacity: 0.3
}
.JS_mainBnr .btn li.on {
z-index: 1;
background: rgba(255, 255, 255, .9) color:#fff;
}
.JS_mainBnr:hover .btn li.on img {
opacity: 1
}
/* Arrow */
.JS_mainBnr .prev {
position: absolute;
top: 285px;
left: 515px;
width: 21.5px;
height: 30px;
background: url('/_wg/img/_arrow/arrowL_50.gif') no-repeat 50% 50% rgba(255, 255, 255, .2);
opacity: 0;
-webkit-opacity: 0;
transition: all .3s ease;
-webkit-transition: all .3s ease;
background-size: 18px 27px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="JS_mainBnr">
<ul class="img">
<li>
<img src="/_wg/img/JS_mainBnr/06P.jpg" alt="">
</li>
<li>
<img src="/_wg/img/JS_mainBnr/08O.jpg" alt="">
</li>
<li>
<img src="/_wg/img/JS_mainBnr/09J.jpg" alt="">
</li>
</ul>
<div id="outer">
<ul class="btn">
<li>
<img src="/_wg/img/JS_mainBnr/01thumba.jpg" width="257px" height="105px">
</li>
<li>
<img src="/_wg/img/JS_mainBnr/02thumba.jpg" width="257px" height="105px">
</li>
<li>
<img src="/_wg/img/JS_mainBnr/03thumba.jpg" width="257px" height="105px">
</li>
</ul>
</div>
<ul class="DB_dir">
<span class="arrow prev"></span>
<span class="arrow next"></span>
</ul>
</div>

.JS_mainBnr .btn {
z-index: 3;
position: absolute;
top: 0;
left: 50%;
margin-left: 370px;
}
.JS_mainBnr .btn li {
margin-left: 60% } /<< DELETE/

Related

Why the div is not moving leftwards using "right" ? in third step

Here, I have code a program that revolves the targeted div in a rectangular path using CSS positions properties in setInterval() method.
Firstly, the div indeed moves rightwards (using left CSS property) and then downwards (using top CSS property) but when the thirds step comes it doesn't move leftwards (using CSS right property). Why is that so?
let a = 0;
let node = document.querySelector(".node");
let inter1 = setInterval(function() {
if (a == 260) {
clearInterval(inter1);
a = 0;
let inter2 = setInterval(function() {
if (a == 639) {
clearInterval(inter2);
a = 260;
let inter3 = setInterval(function() {
if (a == 0) {
clearInterval(inter3);
} else {
a -= 1;
node.style.right = a + "px";
}
}, 1)
} else {
a += 1;
node.style.top = a + "px";
}
}, 1)
} else {
a += 1;
node.style.left = a + "px";
}
}, 1)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: serif;
}
body {
background: black;
color: white;
width: 100vw;
}
.node {
background: dodgerblue;
color: white;
display: inline-block;
width: 100px;
height: 100px;
position: absolute;
}
<div class="node"></div>
Like the user #JavaScript wrote, you should decide for one - left or right.
Therefor you could change right to left in the inter3 statement:
let inter3 = setInterval(function() {
if (a == 0) {
clearInterval(inter3);
} else {
a -= 1;
node.style.left = a + "px";
}
}, 1);
let a = 0;
let node = document.querySelector(".node");
let inter1 = setInterval(function() {
if (a == 260) {
clearInterval(inter1);
a = 0;
let inter2 = setInterval(function() {
if (a == 639) {
clearInterval(inter2);
a = 260;
let inter3 = setInterval(function() {
if (a == 0) {
clearInterval(inter3);
} else {
a -= 1;
node.style.left = a + "px";
}
}, 1)
} else {
a += 1;
node.style.top = a + "px";
}
}, 1)
} else {
a += 1;
node.style.left = a + "px";
}
}, 1)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: serif;
}
body {
background: black;
color: white;
width: 100vw;
}
.node {
background: dodgerblue;
color: white;
display: inline-block;
width: 100px;
height: 100px;
position: absolute;
}
<div class="node"></div>

How to make the slider width change when Resize. JavaScript?

When I change the width of the page it does not stretch in width. Sorry for my English. #How to make the slider width change when Resize.# For some reason, it remembers the first width.
Resize width and transform Please help me. I want to change the width of the screen and have the slider adjust to the width. This code is in pure Javascript. Who can help. I've been racking my head for 3 days, I'm just a beginner.
(function() {
let curTranslateX = 0;
let curPageNum = 0;
let dots = null;
let slideWidth = 0;
let duration = 300;
let pointStart, pointMove, pointEnd;
let slidePositions = [];
let isAutoLoop = false;
let hasArrow = true;
let scrollbar = {
el: '.slide-navbar',
isHide: true,
canClick: true
};
let slideContainer = document.querySelector('.container_slider');
let slideWrapper = slideContainer.querySelector('.slide_wrapper');
let slideItems = [...slideWrapper.querySelectorAll('.slide-item')];
const utils = {
hasClass: function(elem, className) {
return(new RegExp('(\\s|^)' + className + '(\\s|$)')).test(elem.className);
},
addClass: function(elem, className) {
if(!arguments.length) {
return;
}
if(typeof className === 'undefined' || this.hasClass(elem, className)) {
return;
}
let newClasses = elem.className.split(' ');
newClasses.push(className);
elem.className = newClasses.join(' ');
},
removeClass: function(elem, className) {
if(!arguments.length) {
return;
}
if(typeof className === 'undefined' || !this.hasClass(elem, className)) {
return;
}
let classes = elem.className.split(' ');
classes = classes.filter(cls => cls !== className);
elem.className = classes.join(' ');
},
isMobile: function() {
return(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i).test(navigator.userAgent);
}
}
var slide = {
init: (function() {
document.addEventListener('DOMContentLoaded', function() {
dots = [...document.querySelectorAll('.slide-navbar span')];
dots.forEach(dot => {
utils.addClass(dot, 'dot');
});
if(utils.isMobile()) {
pointStart = 'touchstart';
pointMove = 'touchmove';
pointEnd = 'touchend';
} else {
pointStart = 'pointerdown';
pointMove = 'pointermove';
pointEnd = 'pointerup';
}
slide.bindTouchEvent();
slide.setCurrentPage();
}.bind(slide), false);
})(),
setTranslate: function(duration, offsetX, ...yz) {
this.style = `transition-duration: ${duration}ms; transform: translate3d(${offsetX}px, 0px, 0px);`;
curTranslateX = offsetX;
},
setCurrentPage: function(num) {
if(curPageNum !== -1) {
utils.removeClass(dots[curPageNum], 'dot-active');
utils.removeClass(slideItems[curPageNum], 'slide-active');
}
num = (typeof num === 'undefined') ? 0 : num;
curPageNum = num;
utils.addClass(dots[curPageNum], 'dot-active');
utils.addClass(slideItems[curPageNum], 'slide-active');
},
gotoPage: function(num) {
if(num < 0 || num > dots.length - 1) {
return;
}
slide.setTranslate.call(slideWrapper, duration, slidePositions[num]);
setTimeout(() => {
slide.setCurrentPage(num);
}, duration / 2);
},
bindTouchEvent: function() {
slideWidth = slideItems[0].scrollWidth;
slideContainer.style.width = `${slideWidth}px`;
let negMaxWidth = -slideWidth * (slideItems.length - 1);
for(let i = 0, wtd = 0; i < slideItems.length; i++, wtd -= slideWidth) {
slidePositions.push(wtd);
}
let startX,
startY,
initialPos = 0,
moveDist = 0,
direction = 0,
isMove = false,
startT = 0,
isPointOut = true;
slideContainer.addEventListener(pointStart, function(e) {
e.preventDefault();
if(!isPointOut && e.touches.length !== 1) {
return;
}
let startPoint = e.touches[0];
startX = startPoint.pageX;
startY = startPoint.pageY;
initialPos = curTranslateX;
startT = +new Date();
isMove = false;
isPointOut = false;
}.bind(this), false);
slideContainer.addEventListener(pointMove, function(e) {
if(isPointOut) {
return
}
let movePoint = e.touches[0];
let deltaX = movePoint.pageX - startX;
let deltaY = movePoint.pageY - startY;
let offsetX = initialPos + deltaX;
if(offsetX > 0 || offsetX < negMaxWidth) {
offsetX -= (deltaX / 2);
}
this.setTranslate.call(slideWrapper, 0, offsetX);
isMove = true;
deltaX = offsetX - initialPos;
moveDist = deltaX;
direction = deltaX > 0 ? 0 : 1;
}.bind(this), false);
slideContainer.addEventListener(pointEnd, function(e) {
e.preventDefault();
let deltaT = +new Date() - startT;
if(!isMove) {
if(utils.hasClass(e.target, 'slide-button-prev')) {
if(curPageNum === 0) {
return;
}
slide.gotoPage.call(e.target, curPageNum - 1);
} else if(utils.hasClass(e.target, 'slide-button-next')) {
if(curPageNum === dots.length - 1) {
return;
}
slide.gotoPage.call(e.target, curPageNum + 1);
}
return;
}
if(isPointOut) {
return;
}
isPointOut = true;
if(deltaT < 300 || Math.abs(moveDist) > slideWidth / 2) {
offsetX = direction === 0 ? curTranslateX + slideWidth - moveDist : curTranslateX - slideWidth - moveDist;
offsetX = offsetX > 0 ? 0 : offsetX;
offsetX = offsetX < negMaxWidth ? negMaxWidth : offsetX;
} else {
offsetX = curTranslateX - moveDist;
}
slide.setTranslate.call(slideWrapper, duration, offsetX);
let newPageNum = Math.round(Math.abs(offsetX) / slideWidth);
setTimeout(() => {
this.setCurrentPage(newPageNum);
}, duration / 2);
}.bind(this), false);
},
};
})();
.container_box {
max-width: 1400px;
margin: 0 auto;
}
.container_slider {
position: relative;
overflow: hidden;
}
.slide_wrapper {
position: relative;
z-index: 1;
display: flex;
transition-property: transform;
}
.container_slider .slide-item {
z-index: 1;
display: flex;
flex-shrink: 0;
width: 100%;
height: 300px;
user-select: none;
background-size: cover;
background-position: 50%;
background-repeat: no-repeat;
}
.slide-navbar {
position: absolute;
right: 0;
left: 0;
bottom: 0;
text-align: center;
font-size: 0;
z-index: 2;
}
.dot {
display: inline-block;
margin: 0 4px;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.5);
}
.dot-active {
width: 20px;
border-radius: 6px;
background-color: rgba(233, 233, 233, .9);
}
.slide-button-prev,
.slide-button-next {
display: inline-block;
position: absolute;
top: 50%;
width: 40px;
height: 60px;
z-index: 2;
color: rgba(233, 233, 233, .9);
text-align: center;
font-weight: 500;
}
.slide-button-prev {
left: 0;
transform: translateY(-50%);
}
.slide-button-next {
right: 0;
transform: translateY(-50%);
}
<div class="container_box">
<div class="container_slider">
<div class="slide_wrapper">
<div class="slide-item slide-active" style="background-color:green;"></div>
<div class="slide-item" style="background-color:blue;"></div>
<div class="slide-item" style="background-color:black;"></div>
</div>
<div class="control_slider slide-button-prev"><</div>
<div class="control_slider slide-button-next">></div>
<div class="slide-navbar">
<span class="dot dot-active">1</span>
<span class="dot">2</span>
<span class="dot">3</span>
</div>
</div>
</div>
First: I replaced the < and > by > and <:
<div class="control_slider slide-button-prev"><</div>
<div class="control_slider slide-button-next">></div>
To your question:
I found out that in bindTouchEvent: function() {}
exists the line
slideContainer.style.width = ${slideWidth}px;
This line is in charge to set a fix width. If you comment out this line all single slide-items reacts on resize.

Collision detection using pure jQuery is not giving desired output

I am trying to develop a very simple game where the ship (red box) will move left-right when user clicks on playground.
There are some moving walls (black boxes) as obstacles that the ship should avoid colliding with.
If any collision happens, the walls will stop moving and a text will be printed out in console.
I have succeeded to get this as close as I can. But its working sometime, not always. You can see it in the code below, try to collide with wall. Sometime it will stop them and print text, sometime it will just ignore the collision as if nothing happens.
I have no clue why this is happening.
Here is the code.
$('document').ready(function() {
var $totalHeight = $('.inner').height(); //of walls
var $maxHeight = Math.ceil(Math.ceil($totalHeight / 3) - (Math.ceil($totalHeight / 3) * 30) / 100); //30% of total wall height
$('.wall').each(function(i, obj) {
$(this).height($maxHeight);
$('.wall.four').css({
'height': $wallGap
});
})
var $wallGap = Math.ceil($totalHeight / 3) - $maxHeight;
var $wallOneTop = 0;
var $wallTwoTop = $maxHeight + $wallGap;
var $wallThreeTop = ($maxHeight * 2) + ($wallGap * 2);
var $wallFourTop = -$('.wall.four').height() - $wallGap;
$('.wall.one').css({
'top': $wallOneTop
});
$('.wall.two').css({
'top': $wallTwoTop
});
$('.wall.three').css({
'top': $wallThreeTop
});
$('.wall.four').css({
'top': $wallFourTop
});
function moveWall(wallObj) {
var $currentTop = wallObj.position().top;
var $limitTop = $('.inner').height();
if ($currentTop >= $limitTop) {
var $rand = Math.floor(Math.random() * ($maxHeight - $wallGap + 1) + $wallGap);
wallObj.height($rand);
var $top = -(wallObj.height());
} else {
var $top = (wallObj.position().top) + 5;
}
var $collide = checkCollision(wallObj);
wallObj.css({
'top': $top
});
return $collide;
}
var $wallTimer = setInterval(function() {
$('.wall').each(function(i, obj) {
var $status = moveWall($(this));
if ($status == true) {
clearInterval($wallTimer);
}
})
}, 40);
function checkCollision(wallObj) {
var $ship = $('.ship');
var $shipWidth = $ship.width();
var $shipHeight = $ship.height();
var $shipLeft = $ship.position().left;
var $shipRight = $shipLeft + $shipWidth;
var $shipTop = $ship.position().top;
var $shipBottom = $shipTop + $shipHeight;
var $wall = wallObj;
var $wallWidth = wallObj.width();
var $wallHeight = wallObj.height();
var $wallLeft = wallObj.position().left;
var $wallRight = $wallLeft + $wallWidth;
var $wallTop = wallObj.position().top;
var $wallBottom = $wallTop + $wallHeight;
if (
$shipLeft >= $wallRight ||
$shipRight <= $wallLeft ||
$shipTop >= $wallBottom ||
$shipBottom <= $wallTop
) {
return false;
} else {
console.log("dhumm!");
return true;
}
}
$('.outer .inner').click(function() {
var $ship;
$ship = $('.ship');
$shipLeft = $ship.position().left;
$shipRight = $shipLeft + $ship.width();
$inner = $('.inner');
$innerLeft = $inner.position().left;
$innerRight = $innerLeft + $inner.width();
if (($shipLeft < $inner.width() - $ship.width())) {
$ship.animate({
"left": $inner.width() - $ship.width()
}, 500, "linear");
} else if (($shipRight >= $inner.width())) {
$ship.animate({
"left": '0'
}, 500, "linear");
}
});
});
.outer {
background: #fff;
border: 20px solid #efefef;
width: 400px;
height: 600px;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
overflow: hidden;
}
.outer .inner {
background: #fff;
height: 100%;
width: 100%;
margin: auto;
position: relative;
overflow: hidden;
}
.outer .inner .wall {
width: 5px;
position: absolute;
left: 50%;
transform: translateX(-50%);
background: #000;
}
.outer .inner .ship {
width: 15px;
height: 15px;
background: red;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
<div class="wall one"></div>
<div class="wall two"></div>
<div class="wall three"></div>
<div class="wall four"></div>
<div class="ship"></div>
</div>
</div>
As freefomn-m already said.
Check for collision in the animation cycle of the ship, not the walls.
For this I use the second type of parameters for jQuery's .animate method
.animate( properties, options )
I use the "progress" option to check the collision in every movement cycle of the ship.
console.clear();
$('document').ready(function() {
var collided = false;
var collidedWith = null;
var $ship = $('.ship');
var $walls = $('.wall')
var $totalHeight = $('.inner').height(); //of walls
var $maxHeight = Math.ceil(Math.ceil($totalHeight / 3) - (Math.ceil($totalHeight / 3) * 30) / 100); //30% of total wall height
$('.wall').each(function(i, obj) {
$(this).height($maxHeight);
$('.wall.four').css({
'height': $wallGap
});
})
var $wallGap = Math.ceil($totalHeight / 3) - $maxHeight;
var $wallOneTop = 0;
var $wallTwoTop = $maxHeight + $wallGap;
var $wallThreeTop = ($maxHeight * 2) + ($wallGap * 2);
var $wallFourTop = -$('.wall.four').height() - $wallGap;
$('.wall.one').css({
'top': $wallOneTop
});
$('.wall.two').css({
'top': $wallTwoTop
});
$('.wall.three').css({
'top': $wallThreeTop
});
$('.wall.four').css({
'top': $wallFourTop
});
function moveWall(wallObj) {
var $currentTop = wallObj.position().top;
var $limitTop = $('.inner').height();
if ($currentTop >= $limitTop) {
var $rand = Math.floor(Math.random() * ($maxHeight - $wallGap + 1) + $wallGap);
wallObj.height($rand);
var $top = -(wallObj.height());
} else {
var $top = (wallObj.position().top) + 5;
}
// var $collide = checkCollision(wallObj);
wallObj.css({
'top': $top
});
// return $collide;
}
var $wallTimer = setInterval(function() {
$walls.each(function(i, obj) {
moveWall($(this));
if (collided) {
clearInterval($wallTimer);
}
})
}, 40);
function checkCollision() {
var $shipWidth = $ship.width();
var $shipHeight = $ship.height();
var $shipLeft = $ship.position().left;
var $shipRight = $shipLeft + $shipWidth;
var $shipTop = $ship.position().top;
var $shipBottom = $shipTop + $shipHeight;
$('.wall').each(function(i) {
var $wall = $(this);
var $wallWidth = $wall.width();
var $wallHeight = $wall.height();
var $wallLeft = $wall.position().left;
var $wallRight = $wallLeft + $wallWidth;
var $wallTop = $wall.position().top;
var $wallBottom = $wallTop + $wallHeight;
if (
$shipLeft < $wallRight &&
$shipRight > $wallLeft &&
$shipTop < $wallBottom &&
$shipBottom > $wallTop
) {
console.log("dhumm!");
collided = true;
collidedWith = $wall
$wall.addClass('crashed')
$ship.addClass('crashed')
$ship.stop();
return false;
}
})
}
$('.outer .inner').click(function() {
var $ship;
$ship = $('.ship');
$shipLeft = $ship.position().left;
$shipRight = $shipLeft + $ship.width();
$inner = $('.inner');
$innerLeft = $inner.position().left;
$innerRight = $innerLeft + $inner.width();
if (($shipLeft < $inner.width() - $ship.width())) {
$ship.animate({
"left": $inner.width() - $ship.width()
}, {
"duration": 500,
"easing": "linear",
"progress": checkCollision,
});
} else if (($shipRight >= $inner.width())) {
$ship.animate({
"left": '0'
}, {
"duration": 500,
"easing": "linear",
"progress": checkCollision,
});
}
});
});
.outer {
background: #fff;
border: 20px solid #efefef;
width: 400px;
height: 600px;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
overflow: hidden;
}
.outer .inner {
background: #fff;
height: 100%;
width: 100%;
margin: auto;
position: relative;
overflow: hidden;
}
.outer .inner .wall {
width: 5px;
position: absolute;
left: 50%;
transform: translateX(-50%);
background: #000;
}
.outer .inner .wall.crashed {
background: red;
}
.outer .inner .ship {
width: 15px;
height: 15px;
background: orange;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.outer .inner .ship.crashed {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
<div class="wall one"></div>
<div class="wall two"></div>
<div class="wall three"></div>
<div class="wall four"></div>
<div class="ship"></div>
</div>
</div>
As a recommendation how I would do this from scratch.
Use an update cycle that is called by either setInterval or setTimeout, or even better with requestAnimationFrame. The updatecycle would be responsible for the time progress and orchestrate the different objects. The structure would be like this.
jQuery(function($) { // same as $('document').ready()
var ship = ...;
var boundaries = ...;
var walls = ...;
var clickEvents = [];
document.addEventListener('click', function(e) {clickEvents.push(e)})
var handleEvents = function() {}
var setupWalls = function () {}
var setupShip= function () {}
var moveWalls = function () {}
var moveShip = function () {}
var checkCollision() {}
var setup = function() {
setupWalls();
setupShip();
// set the initial positions of the ships and the walls
}
var update = function() {
handleEvents();
moveWalls();
moveShips();
var collided = checkCollision();
if (!collided) {
setTimeout(update, 30);
}
}
setup();
update();
})

Drag image within container, not moving with mouse, slightly quicker

I have got a Vue component where i can zoom in on an image and then move it around the container. When zoomed there is also a small viewport to show what part of the image is visible. However when moving the image around it is moving faster than the mouse, i'm guessing this is due to using the scale transform.
I also feel like when i'm clicking and dragging on the viewport I shouldn't be reversing the values twice however this seems to be the only way to get it moving the square with the mouse.
Vue.component('test', {
template: '#template',
data: function() {
return {
loading: true,
loop: true,
speed: 8,
speedController: 0,
zoomEnabled: true,
zoomLevels: [1, 1.5, 2, 2.5, 3],
zoomLevel: 1,
frame: 1,
images: [],
imagesPreloaded: 0,
reverse: false,
viewportScale: 0.3,
viewportEnabled: true,
viewportOpacity: 0.8,
lastX: 0,
lastY: 0,
startX: 0,
startY: 0,
translateX: 0,
translateY: 0,
isMoving: false,
isDragging: false,
};
},
mounted() {
window.addEventListener('mouseup', this.handleEnd);
window.addEventListener('touchend', this.handleEnd);
},
beforeDestroy() {
window.removeEventListener('mouseup', this.handleEnd);
window.removeEventListener('touchend', this.handleEnd);
},
methods: {
handleSlider(event) {
this.frame = Number(event.target.value);
},
zoom(direction) {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
if (this.zoomLevels[this.zoomLevels.indexOf(closest) + direction] === undefined) {
return;
}
let current = this.zoomLevels.indexOf(closest);
let index = current += direction;
if (direction === 0) {
index = 0;
}
this.zoomLevel = this.zoomLevels[index];
window.requestAnimationFrame(() => {
this.translate(null, this.$refs.image, true);
});
},
zoomWheel($event) {
$event.preventDefault();
this.zoomLevel += $event.deltaY * -0.01;
if (this.zoomLevel < 1) {
this.zoomLevel = 1;
}
let maxZoom = this.zoomLevels[this.zoomLevels.length - 1];
this.zoomLevel = Math.min(Math.max(.125, this.zoomLevel), maxZoom);
window.requestAnimationFrame(() => {
this.translate(null, this.$refs.image, true);
});
},
handleStart($event) {
$event.preventDefault();
if ($event.button && $event.button !== 0) {
return;
}
this.isMoving = true;
this.isDragging = true;
this.startX = $event.pageX || $event.touches[0].pageX;
this.startY = $event.pageY || $event.touches[0].pageY;
},
handleMove($event, viewport) {
if ($event.button && $event.button !== 0) {
return;
}
if (this.isMoving && this.isDragging) {
const positions = {
x: $event.pageX || $event.touches[0].pageX,
y: $event.pageY || $event.touches[0].pageY
}
if (this.zoomLevel !== 1) {
this.translate(positions, $event.target, null, viewport);
}
if (this.zoomLevel === 1) {
this.changeFrame(positions);
}
}
},
handleEnd($event) {
if ($event.button && $event.button !== 0) {
return;
}
this.isMoving = false;
},
translate(positions, element, zooming, viewport) {
if (positions === null) {
positions = {
x: this.startX,
y: this.startY
};
}
let move = {
x: Math.floor(positions.x - this.startX),
y: Math.floor(positions.y - this.startY)
};
// Reverse Mouse Movement
if (viewport) {
move.x = -move.x;
move.y = -move.y;
}
let image = element.getBoundingClientRect();
let container = element.parentNode.getBoundingClientRect();
let translate = {
left: Math.floor((container.left - image.left) - (move.x * this.zoomLevel)),
right: Math.floor((container.right - image.right) - (move.x * this.zoomLevel)),
top: Math.floor((container.top - image.top) - (move.y * this.zoomLevel)),
bottom: Math.floor((container.bottom - image.bottom) - (move.y * this.zoomLevel))
};
// Reverse Translate Movement
if (viewport) {
translate.left = -translate.left;
translate.right = -translate.right;
translate.top = -translate.top;
translate.bottom = -translate.bottom;
}
if (zooming) {
if (translate.left <= 0) {
this.translateX += Math.floor(translate.left);
}
if (translate.right >= 0) {
this.translateX += Math.floor(translate.right);
}
if (translate.top <= 0) {
this.translateY += Math.floor(translate.top);
}
if (translate.bottom >= 0) {
this.translateY += Math.floor(translate.bottom);
}
}
if (translate.left >= 0 && translate.right <= 0) {
this.translateX += Math.floor(move.x);
}
if (translate.top >= 0 && translate.bottom <= 0) {
this.translateY += Math.floor(move.y);
}
this.startX = positions.x;
this.startY = positions.y;
}
},
computed: {
nextZoomLevel: function() {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
if (this.zoomLevels.indexOf(closest) === this.zoomLevels.length - 1) {
return this.zoomLevels[0];
}
return this.zoomLevels[this.zoomLevels.indexOf(closest) + 1];
},
viewportTransform: function() {
if (this.viewportEnabled) {
let translateX = -((this.translateX * this.viewportScale) * this.zoomLevel);
let translateY = -((this.translateY * this.viewportScale) * this.zoomLevel);
return `scale(${1 / this.zoomLevel}) translateX(${translateX}px) translateY(${translateY}px)`;
}
},
transform: function() {
return `scale(${this.zoomLevel}) translateX(${this.translateX}px) translateY(${this.translateY}px)`;
},
canZoomIn: function() {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
return this.zoomLevels[this.zoomLevels.indexOf(closest) + 1] === undefined
},
canZoomOut: function() {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
return this.zoomLevels[this.zoomLevels.indexOf(closest) + -1] === undefined
}
}
});
window.vue = new Vue({el: '#app'});
.media-360-viewer {
position: relative;
overflow: hidden;
background: #000;
}
.media-360-viewer>img {
width: 100%;
}
.media-360-viewer>img.canTranslate {
cursor: grab;
}
.media-360-viewer>img.isTranslating {
cursor: grabbing;
}
.media-360-viewer>img.canRotate {
cursor: w-resize;
}
.media-360-viewer__loader {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
.media-360-viewer__loader * {
user-select: none;
}
.media-360-viewer__loader>svg {
width: 100%;
height: 100%;
transform: rotate(270deg);
}
.media-360-viewer__loader--text {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.media-360-viewer__loader--text p {
font-size: 100%;
font-weight: bold;
color: #fff;
}
.media-360-viewer__loader--text p.large {
font-size: 150%;
}
.media-360-viewer__loader--background {
stroke-dasharray: 0;
stroke-dashoffset: 0;
stroke: rgba(0, 0, 0, 0.7);
stroke-width: 25px;
}
.media-360-viewer__loader--cover {
stroke-dasharray: 200%;
stroke: #848484;
stroke-width: 15px;
stroke-linecap: round;
}
.media-360-viewer__loader--background,
.media-360-viewer__loader--cover {
fill: transparent;
}
.media-360-viewer__viewport {
position: absolute;
top: 10px;
left: 10px;
z-index: 2;
border: 1px solid black;
overflow: hidden;
}
.media-360-viewer__viewport--image {
width: 100%;
pointer-events: none;
}
.media-360-viewer__viewport--zoom {
position: absolute;
bottom: 5px;
right: 5px;
color: #fff;
z-index: 3;
font-size: 12px;
pointer-events: none;
}
.media-360-viewer__viewport--square {
border: 1px solid black;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
box-shadow: rgba(0, 0, 0, 0.5) 0 0 0 10000px;
cursor: grab;
transition: background ease-in-out 0.1s;
}
.media-360-viewer__viewport--square:hover {
background: rgba(255, 255, 255, 0.2);
}
.media-360-viewer__header {
position: absolute;
top: 10px;
left: 0;
width: 100%;
}
.media-360-viewer__tools {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 10px;
}
.media-360-viewer__tools>a {
margin: 0 5px;
color: #000;
background: #fff;
border-radius: 50%;
width: 40px;
text-align: center;
line-height: 40px;
}
.media-360-viewer__tools>a[disabled] {
opacity: .5;
cursor: not-allowed;
}
.media-360-viewer__tools>a[disabled]:hover {
color: #000;
background: #fff;
}
.media-360-viewer__tools>a:hover {
background: #000;
color: #fff;
}
.media-360-viewer__tools--autoplay:before {
font-family: 'ClickIcons';
content: '\ea81';
}
.media-360-viewer__tools--autoplay.active:before {
content: '\eb48';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<test></test>
</div>
<script type="text/x-template" id="template">
<div class="media-360-viewer" ref="container">
<transition name="fade">
<div class="media-360-viewer__viewport" v-if="zoomLevel > 1 && viewportEnabled" :style="{ width: (viewportScale * 100) + '%' }">
<img tabindex="1" draggable="false" alt="Viewport" class="media-360-viewer__viewport--image" src="https://www.bennetts.co.uk/-/media/bikesocial/2019-september-images/2020-yamaha-yzf-r1-and-r1m-review/2020-yamaha-r1-and-r1m_005.ashx?h=493&w=740&la=en&hash=F97CD240F0DDFA9540E912DCF7F07019017035C6">
<span class="media-360-viewer__viewport--zoom">
x{{ Math.round(zoomLevel * 10) / 10 }}
</span>
<span :style="{ transform: viewportTransform }" #mouseup="handleEnd" #mousedown="handleStart" #mousemove="handleMove($event, true)" #touchstart="handleStart" #touchend="handleEnd" #touchmove="handleMove($event, true)" class="media-360-viewer__viewport--square"></span>
</div>
</transition>
<img tabindex="1" ref="image" draggable="false" src="https://www.bennetts.co.uk/-/media/bikesocial/2019-september-images/2020-yamaha-yzf-r1-and-r1m-review/2020-yamaha-r1-and-r1m_005.ashx?h=493&w=740&la=en&hash=F97CD240F0DDFA9540E912DCF7F07019017035C6" :style="{ transform: transform }" :class="{
canTranslate: zoomLevel > 1 && zoomEnabled,
canRotate: zoomLevel === 1,
isTranslating: zoomLevel > 1 && zoomEnabled && isMoving
}" #mouseup="handleEnd" #mousedown="handleStart" #mousemove="handleMove" #touchstart="handleStart" #touchend="handleEnd" #touchmove="handleMove" #dblclick="zoom" #wheel="zoomWheel" alt="360 Image" />
</div>
</script>
Does anyone know how I can fix this?
Edit
Below is the updated code with the changes suggested by the accepted answer, only issue now is the viewport square going out of frame.
Vue.component('test', {
template: '#template',
data: function() {
return {
loading: true,
loop: true,
speed: 8,
speedController: 0,
zoomEnabled: true,
zoomLevels: [1, 1.5, 2, 2.5, 3],
zoomLevel: 1,
frame: 1,
images: [],
imagesPreloaded: 0,
reverse: false,
viewportScale: 0.3,
viewportEnabled: true,
viewportOpacity: 0.8,
lastX: 0,
lastY: 0,
startX: 0,
startY: 0,
translateX: 0,
translateY: 0,
isMoving: false,
isDragging: false,
};
},
mounted() {
window.addEventListener('mouseup', this.handleEnd);
window.addEventListener('touchend', this.handleEnd);
},
beforeDestroy() {
window.removeEventListener('mouseup', this.handleEnd);
window.removeEventListener('touchend', this.handleEnd);
},
methods: {
zoom(direction) {
// todo: Load high res image based on zoom level
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
if (this.zoomLevels[this.zoomLevels.indexOf(closest) + direction] === undefined) {
return;
}
let current = this.zoomLevels.indexOf(closest);
let index = current += direction;
if (direction === 0) {
index = 0;
}
this.zoomLevel = this.zoomLevels[index];
this.translate(null, this.$refs.image, true);
},
zoomWheel($event) {
$event.preventDefault();
this.zoomLevel += $event.deltaY * -0.01;
if (this.zoomLevel < 1) {
this.zoomLevel = 1;
}
let maxZoom = this.zoomLevels[this.zoomLevels.length - 1];
this.zoomLevel = Math.min(Math.max(.125, this.zoomLevel), maxZoom);
this.translate(null, this.$refs.image, true);
},
handleStart($event) {
$event.preventDefault();
if ($event.button && $event.button !== 0) {
return;
}
this.isMoving = true;
this.isDragging = true;
this.startX = $event.pageX || $event.touches[0].pageX;
this.startY = $event.pageY || $event.touches[0].pageY;
},
handleMove($event, viewport) {
if ($event.button && $event.button !== 0) {
return;
}
if (this.isMoving && this.isDragging) {
const positions = {
x: $event.pageX || $event.touches[0].pageX,
y: $event.pageY || $event.touches[0].pageY
}
if (this.zoomLevel !== 1) {
this.translate(positions, $event.target, null, viewport);
}
}
},
handleEnd($event) {
if ($event.button && $event.button !== 0) {
return;
}
this.isMoving = false;
},
translate(positions, element, zooming, viewport) {
window.requestAnimationFrame(() => {
positions = positions || {
x: this.startX,
y: this.startY
};
if (viewport) {
this._translateFromViewport(positions, element);
} else {
this._translateFromImage(positions, element, zooming);
}
this.startX = positions.x;
this.startY = positions.y;
});
},
_translateFromViewport: function(positions, element) {
let move = {
x: positions.x - this.startX,
y: positions.y - this.startY
};
let box = element.getBoundingClientRect();
let container = element.parentNode.getBoundingClientRect();
let translate = {
left: (container.left - box.left) - ((move.x * this.viewportScale) * this.zoomLevel),
right: (container.right - box.right) - ((move.x * this.viewportScale) * this.zoomLevel),
top: (container.top - box.top) - ((move.y * this.viewportScale) * this.zoomLevel),
bottom: (container.bottom - box.bottom) - ((move.y * this.viewportScale) * this.zoomLevel)
};
if (translate.left <= 0 && translate.right >= 0) {
this.translateX -= move.x / this.viewportScale;
}
if (translate.top <= 0 && translate.bottom >= 0) {
this.translateY -= move.y / this.viewportScale
}
},
_translateFromImage: function(positions, element, zooming) {
let move = {
x: Math.floor(positions.x - this.startX),
y: Math.floor(positions.y - this.startY)
};
let image = element.getBoundingClientRect();
let container = element.parentNode.getBoundingClientRect();
let translate = {
left: (container.left - image.left) - (move.x * this.zoomLevel),
right: (container.right - image.right) - (move.x * this.zoomLevel),
top: (container.top - image.top) - (move.y * this.zoomLevel),
bottom: (container.bottom - image.bottom) - (move.y * this.zoomLevel)
};
if (zooming) {
if (translate.left <= 0) {
this.translateX += translate.left;
}
if (translate.right >= 0) {
this.translateX += translate.right;
}
if (translate.top <= 0) {
this.translateY += translate.top;
}
if (translate.bottom >= 0) {
this.translateY += translate.bottom;
}
}
if (translate.left >= 0 && translate.right <= 0) {
this.translateX += move.x / this.zoomLevel;
}
if (translate.top >= 0 && translate.bottom <= 0) {
this.translateY += move.y / this.zoomLevel;
}
},
},
computed: {
preloadProgress: function() {
return Math.floor(this.imagesPreloaded / this.images.length * 100);
},
currentPath: function() {
return this.images[this.frame - 1];
},
nextZoomLevel: function() {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
if (this.zoomLevels.indexOf(closest) === this.zoomLevels.length - 1) {
return this.zoomLevels[0];
}
return this.zoomLevels[this.zoomLevels.indexOf(closest) + 1];
},
viewportTransform: function() {
if (this.viewportEnabled) {
let translateX = -((this.translateX * this.viewportScale) * this.zoomLevel);
let translateY = -((this.translateY * this.viewportScale) * this.zoomLevel);
return `scale(${1 / this.zoomLevel}) translateX(${translateX}px) translateY(${translateY}px)`;
}
},
transform: function() {
return `scale(${this.zoomLevel}) translateX(${this.translateX}px) translateY(${this.translateY}px)`;
},
canZoomIn: function() {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
return this.zoomLevels[this.zoomLevels.indexOf(closest) + 1] === undefined
},
canZoomOut: function() {
const closest = this.zoomLevels.reduce((a, b) => {
return Math.abs(b - this.zoomLevel) < Math.abs(a - this.zoomLevel) ? b : a;
});
return this.zoomLevels[this.zoomLevels.indexOf(closest) + -1] === undefined
}
}
});
window.vue = new Vue({
el: '#app'
});
.media-360-viewer {
position: relative;
overflow: hidden;
background: #000;
width: 500px;
}
.media-360-viewer__image {
width: 100%;
}
.media-360-viewer__image.canTranslate {
cursor: grab;
}
.media-360-viewer__image.isTranslating {
cursor: grabbing;
}
.media-360-viewer__image.canRotate {
cursor: w-resize;
}
.media-360-viewer__loader {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
.media-360-viewer__loader * {
user-select: none;
}
.media-360-viewer__loader > svg {
width: 100%;
height: 100%;
transform: rotate(270deg);
}
.media-360-viewer__loader--text {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.media-360-viewer__loader--text p {
font-size: 100%;
font-weight: bold;
color: #fff;
}
.media-360-viewer__loader--text p.large {
font-size: 150%;
}
.media-360-viewer__loader--background {
stroke-dasharray: 0;
stroke-dashoffset: 0;
stroke: rgba(0, 0, 0, 0.7);
stroke-width: 25px;
}
.media-360-viewer__loader--cover {
stroke-dasharray: 200%;
stroke: #848484;
stroke-width: 15px;
stroke-linecap: round;
}
.media-360-viewer__loader--background,
.media-360-viewer__loader--cover {
fill: transparent;
}
.media-360-viewer__viewport {
position: absolute;
top: 10px;
left: 10px;
z-index: 2;
overflow: hidden;
}
.media-360-viewer__viewport--image {
width: 100%;
pointer-events: none;
}
.media-360-viewer__viewport--zoom {
position: absolute;
bottom: 5px;
right: 5px;
color: #fff;
z-index: 3;
font-size: 12px;
pointer-events: none;
}
.media-360-viewer__viewport--square {
display: block;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
box-shadow: rgba(0, 0, 0, 0.8) 0 0 0 10000px;
cursor: grab;
transition: background ease-in-out 0.1s;
}
.media-360-viewer__viewport--square:hover {
background: rgba(255, 255, 255, 0.2);
}
.media-360-viewer__tools {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 10px;
}
.media-360-viewer__tools > a {
margin: 0 5px;
color: #000;
background: #fff;
border-radius: 50%;
width: 40px;
text-align: center;
line-height: 40px;
}
.media-360-viewer__tools > a[disabled] {
opacity: .5;
cursor: not-allowed;
}
.media-360-viewer__tools > a[disabled]:hover {
color: #000;
background: #fff;
}
.media-360-viewer__tools > a:hover {
background: #000;
color: #fff;
}
.media-360-viewer__tools--autoplay:before {
font-family: 'ClickIcons';
content: '\ea81';
}
.media-360-viewer__tools--autoplay.active:before {
content: '\eb48';
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<test></test>
</div>
<script type="text/x-template" id="template">
<div class="media-360-viewer" ref="container">
<transition name="fade">
<div class="media-360-viewer__viewport" v-if="zoomLevel > 1 && viewportEnabled" :style="{ width: (viewportScale * 100) + '%' }">
<img tabindex="1" draggable="false" alt="Viewport" class="media-360-viewer__viewport--image" src="https://www.bennetts.co.uk/-/media/bikesocial/2019-september-images/2020-yamaha-yzf-r1-and-r1m-review/2020-yamaha-r1-and-r1m_005.ashx?h=493&w=740&la=en&hash=F97CD240F0DDFA9540E912DCF7F07019017035C6">
<span class="media-360-viewer__viewport--zoom">
x{{ Math.round(zoomLevel * 10) / 10 }}
</span>
<span :style="{ transform: viewportTransform }" #mouseup="handleEnd" #mousedown="handleStart" #mousemove="handleMove($event, true)" #touchstart="handleStart" #touchend="handleEnd" #touchmove="handleMove($event, true)" class="media-360-viewer__viewport--square"></span>
</div>
</transition>
<img tabindex="1" ref="image" draggable="false" src="https://www.bennetts.co.uk/-/media/bikesocial/2019-september-images/2020-yamaha-yzf-r1-and-r1m-review/2020-yamaha-r1-and-r1m_005.ashx?h=493&w=740&la=en&hash=F97CD240F0DDFA9540E912DCF7F07019017035C6"
:style="{ transform: transform }" :class="{
canTranslate: zoomLevel > 1 && zoomEnabled,
canRotate: zoomLevel === 1,
isTranslating: zoomLevel > 1 && zoomEnabled && isMoving
}" #mouseup="handleEnd" #mousedown="handleStart" #mousemove="handleMove" #touchstart="handleStart" #touchend="handleEnd" #touchmove="handleMove" #dblclick="zoom" #wheel="zoomWheel" alt="360 Image" />
</div>
</script>
Math.floor only when necessary
A part of this problem is a result of calling Math.floor all the time. Each time you call Math.floor your next calculations will be less accurate.
If you still want to round numbers, do it only at the end of your calculations chain or even in the place where you are using the variable. For example:
transform: function() {
const translateX = Math.floor(this.translateX)
const translateY = Math.floor(this.translateY)
return `scale(${this.zoomLevel}) translateX(${translateX}px) translateY(${translateY}px)`;
}
Scaling factor
However when moving the image around it is moving faster than the mouse
This can be fixed by dividing number you're adding to the translate value by scale factor, which is determined by zoomLevel like so:
if (translate.left >= 0 && translate.right <= 0) {
this.translateX += move.x / this.zoomLevel
}
if (translate.top >= 0 && translate.bottom <= 0) {
this.translateY += move.y / this.zoomLevel
}
Scaling factor - viewport
Viewport is still somehow broken too because of scaling, we need to adjust translation value too, but this time not using zoomLevel but scale of the viewport which is stored in this.viewportScale. So, merging two of solutions together we now have code like this:
if (translate.left >= 0 && translate.right <= 0) {
if (viewport) {
this.translateX += move.x / this.viewportScale
} else {
this.translateX += move.x / this.zoomLevel
}
}
if (translate.top >= 0 && translate.bottom <= 0) {
if (viewport) {
this.translateY += move.y / this.viewportScale
} else {
this.translateY += move.y / this.zoomLevel
}
}
Reversing values
I also feel like when i'm clicking and dragging on the viewport I shouldn't be reversing the values twice
I don't think that there is a better way to do it unless you want to make two inner translate functions that will handle translation depending on the input source (viewport or image). It will be definetely cleaner approach to coding. For example if in future you would like to write some viewport specific code you will not need to include another and another if. Your function could like like so:
translate (positions, element, zooming, viewport) {
positions = positions || {
x: this.startX,
y: this.startY
}
if (viewport) {
this._translateFromViewport(positions, element, zooming)
} else {
this._translateFromImage(positions, element, zooming)
}
this.startX = positions.x
this.startY = positions.y
}
where _translateFromViewport and _translateFromImage functions hold feature specific code.

Need help to limit how many tiles and target spawn in this game

I got some simple bomberman game from code pen.For my study,i need to limit how many tiles and target.For tiles max 32 and target 7 (tiles grey & target red).
Here the source : codepen.io/Digiben/pen/oGYGrx
I dont understand how the script create the target and tiles with random algoritm.
Thanks for anyone who look this thread.
window.onload = function(){
//Map Kelas
class Map {
constructor (nbX, nbY, tileSize){
this.nbX = nbX;
this.nbY = nbY;
this.mapArray = new Array(this.nbX);
this.tileSize = tileSize;
this.map = document.getElementById('map');
}
init() {
console.log('Map size: ' + this.nbX * this.nbY);
let i = 0;
let j = 0;
let bool = null;
this.map.style.width = (this.tileSize * this.nbX) + 'px';
this.map.style.height = this.tileSize * this.nbY + 'px';
for (i = 0; i < this.nbX; i++) {
this.mapArray[i] = new Array(this.nbY);
for (j = 0; j < this.nbY; j++) {
bool = Math.random() >= 0.7 ? true : false;
if (bool) {
for (var z = Things.length - 1; i >= 0; i-) {
Things[i]
}
} else if (!bool) {
this.mapArray[i][j] = 1;
}
}
}
}
appendTile(i, j) {
let tile = document.createElement('div');
this.map.appendChild(tile);
tile.style.width = this.tileSize + 'px';
tile.style.height = this.tileSize + 'px';
tile.classList.add('tile');
tile.style.left = (i * this.tileSize) + 'px';
tile.style.top = (j * this.tileSize) + 'px';
}
getMapArray () {
return this.mapArray;
}
getMapSize () {
return {sizeX: this.nbX, sizeY:this.nbY}
}
}
//Create Target
class Target {
constructor (map, tileSize) {
this.mapArray = map.getMapArray();
this.playerSpace = map.getMapSize();
this.targetsArray = new Array();
this.possiblePositionToStartX = new Array();
this.possiblePositionToStartY = new Array();
this.tileSize = tileSize;
this.map = document.getElementById('map');
this.totalTargets = 0;
}
getTotalTargets(){
return this.totalTargets;
}
//Show Total Target
showTotalTargets () {
let totalDiv = document.querySelector('#score strong');
totalDiv.innerHTML = ' / ' + this.totalTargets;
}
showTargets(i, j) {
let tile = document.createElement('div');
this.map.appendChild(tile);
tile.classList.add('target');
tile.style.width = this.tileSize + 'px';
tile.style.height = this.tileSize + 'px';
// set attribute to identify the target when we need to remove it
tile.setAttribute('data-pos', i + ':' + j );
// positionning and styling
tile.style.left = (i * this.tileSize) + 'px';
tile.style.top = (j * this.tileSize) + 'px';
tile.style.backgroundColor = 'red';
tile.style.opacity = 0.5;
}
createTargets() {
//Target looping
for (var i = 1; i < this.playerSpace.sizeX-1; i++) {
//Maks Target 2D 10x10
this.targetsArray[i] = new Array();
if (i == 1) this.targetsArray[i-1] = new Array();
if (i == 8) this.targetsArray[i+1] = new Array();
for (var j = 1; j < this.playerSpace.sizeY-1; j++) {
this.targetsArray[i][j] = 1;
//Target aLgorithm
//Player dont Looping On red Zone
this.possiblePositionToStartX.push(i+1);
this.possiblePositionToStartY.push(j+1);
//Target Array if 0 to display Win on the End
this.targetsArray[i][j] = 0;
//Total Targets
this.totalTargets++;
//Show Target On map
this.showTargets(i, j);
}
}
}
//Show Total Targets
this.showTotalTargets();
}
// Start Player
getPossiblePosToStart() {
//Random Start PLayer
let xPos = this.possiblePositionToStartX[Math.floor(Math.random() * (this.possiblePositionToStartX.length))];
let yPos = this.possiblePositionToStartY[Math.floor(Math.random() * (this.possiblePositionToStartY.length))];
return {x: xPos, y: yPos}
}
//Player Array
getTargetsArray(){
return this.targetsArray;
}
}
//PLayer CLass
class Player {
constructor (mapArray, map, targets, tileSize) {
this.positionArray = mapArray;
this.position = {x: 0, y: 0}
this.playerDiv = document.getElementById('player');
this.playerDiv.style.left = 0;
this.playerDiv.style.top = 0;
this.playerDiv.style.right = 0;
this.playerDiv.style.bottom = 0;
this.playerDiv.style.width = tileSize + 'px';
this.playerDiv.style.height = tileSize + 'px';
this.playerSpace = map.getMapSize();
this.playerMap = map.getMapArray();
this.score = 0;
this.targetsArray = targets.getTargetsArray();
this.totalTargets = targets.getTotalTargets();
this.tileSize = tileSize;
}
//Record Posisition Player
recordPosition(mapArray){
this.positionArray = mapArray;
}
//Reset Score when Restart The game
static resetScore() {
let scoreSpan = document.querySelector('#score span'); scoreSpan.innerHTML = '0';
}
//Set Palyer
setPosition (position){
this.playerDiv.style.left = (position.x * this.tileSize) + 'px';
this.playerDiv.style.top = (position.y * this.tileSize) + 'px';
this.position.x = position.x;
this.position.y = position.y;
}
getPosition() {
return this.position;
}
//Limt Map
moveRight() {
if(this.position.x > this.playerSpace.sizeX-2) return false;
if(this.positionArray[this.position.x+1][this.position.y] != 0){
this.position.x++;
let nb = this.playerDiv.style.left.split('px');
this.playerDiv.style.left = (parseInt(nb[0]) + this.tileSize) + 'px';
console.log('Droite | X : ' + this.playerDiv.style.left);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
moveDown() {
if(this.position.y > this.playerSpace.sizeY-2) return false;
if(this.positionArray[this.position.x][this.position.y+1] != 0){
this.position.y++;
let nb = this.playerDiv.style.top.split('px');
this.playerDiv.style.top = (parseInt(nb[0]) + this.tileSize) + 'px';
console.log('Bas | Y : ' + this.playerDiv.style.top);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
moveLeft() {
if(this.position.x == 0) return false;
if(this.positionArray[this.position.x-1][this.position.y] != 0){
this.position.x--;
let nb = this.playerDiv.style.left.split('px');
this.playerDiv.style.left = (parseInt(nb[0]) - this.tileSize) + 'px';
console.log('Gauche | X : ' + this.playerDiv.style.left);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
moveUp() {
if(this.position.y <= 0) return false;
if(this.positionArray[this.position.x][this.position.y-1] != 0){
this.position.y--;
let nb = this.playerDiv.style.top.split('px');
this.playerDiv.style.top = (parseInt(nb[0]) - this.tileSize) + 'px';
console.log('Haut | Y : ' + this.playerDiv.style.top);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
//Update Score
updateScore () {
let scoreDiv = document.querySelector('#score span');
scoreDiv.innerHTML = this.score;
//Winner Message
if(this.score == this.totalTargets) document.querySelector ('#win').classList.add('show');
console.log('Score : ' + this.score);
}
//Update Target Array
updateTargetsArray (posx, posy){
this.targetsArray[posx][posy] = 1;
console.log('Array state : ');
console.log(this.targetsArray);
}
//Remove Target
removeTarget(posx, posy) {
let targetToRemove = document.querySelectorAll('.target');
let coords = posx + ':' + posy;
let attr = '';
//Loop To find Right Target accroding Coordinates Player
for (var i = 0; i< targetToRemove.length; i++) {
attr = targetToRemove[i].getAttribute('data-pos');
if(attr == coords) {
targetToRemove[i].remove();
//Update Score
this.score++;
this.updateScore();
}
}
//Remove Html node (Remove Array Target)
if(this.targetsArray[posx][posy] == 0){
this.targetsArray[posx][posy] == 1;
}
}
//Plant Bomb
plantBomb(){
//Make Child Bomb
let map = document.getElementById('map');
let bomb = document.createElement('div');
map.appendChild(bomb);
bomb.style.width = this.tileSize + 'px';
bomb.style.height = this.tileSize + 'px';
//Posision Bomb
bomb.classList.add('bomb');
bomb.style.left = (this.position.x * this.tileSize) + 'px';
bomb.style.top = (this.position.y * this.tileSize) + 'px';
//Variables
var posx = this.position.x;
var posy = this.position.y;
var that = this;
var timer = setInterval(bombTimer, 500, posx, posy, that);
var iter = 0;
//BombTimer
function bombTimer() {
switch (iter) {
case 1:
bomb.classList.add('waiting');
break;
case 2:
bomb.classList.add('before');
bomb.classList.remove('waiting');
break;
case 3:
bomb.classList.add('explode');
bomb.classList.remove('before');
break;
case 4:
clearInterval(timer);
bomb.remove();
that.updateTargetsArray(posx, posy);
that.removeTarget(posx, posy);
default:
break;
}
iter++;
}
}
}
//Game Class
class Game {
constructor (tileSize, mapX, mapY) {
//Create Map
var map = new Map(mapX,mapY, tileSize);
map.init();
//Create Target
var targets = new Target(map, tileSize);
targets.createTargets();
//Create PLayer
var player = new Player(map.getMapArray(), map, targets, tileSize);
//Place The player
player.setPosition(targets.getPossiblePosToStart());
//Keyboard Events
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {
player.moveUp();
}
else if (e.keyCode == '40') {
player.moveDown();
}
else if (e.keyCode == '37') {
player.moveLeft();
}
else if (e.keyCode == '39') {
player.moveRight();
}
else if (e.keyCode == '32') {
player.plantBomb();
}
}
}
//Destroy Game
static destroy () {
let targets = document.querySelectorAll('.target');
let tiles = document.querySelectorAll('.tile');
Player.resetScore();
if(tiles){
targets.forEach(function(element) {
element.remove();
});
tiles.forEach(function(element) {
element.remove();
});
}
}
}
class Session {
constructor () {
this.totalTargets = 0;
this.players = {};
this.restartBtn = document.querySelector('#restart');
this.restartBtn.addEventListener('click', function() {
Session.restart();
});
}
static restart () {
Game.destroy();
var game = new Game(25, 10, 10);
}
}
var session = new Session();
};
#map {
width: 500px;
height: 500px;
background: lightgrey;
position: relative;
margin: auto;
}
#game {
width: 500px;
height: 500px;
position: relative;
margin: auto;
}
#map .tile {
width: 50px;
height: 50px;
background: grey;
position: absolute;
outline: 1px solid #eee;
}
#map .target {
width: 50px;
height: 50px;
background: red;
position: absolute;
outline: 1px solid #eee;
}
#map #player {
border-radius: 25%;
width: 50px;
height: 50px;
position: absolute;
background: #222222;
z-index: 1;
transition: 0.1s;
}
.bomb {
border-radius: 100%;
width: 50px;
height: 50px;
position: absolute;
background: #333;
z-index: 1;
transition: 0.3s ease;
}
.bomb.waiting {
animation: waiting 2s infinite;
}
.bomb.before {
animation: before 1s infinite;
}
.bomb.explode {
animation: explode 1s infinite;
}
#score p, #score span {
font-family: sans-serif;
color: #333;
font-size: 16px;
display: inline;
}
#keyframes waiting {
0% {
transform: scale(0.9);
}
100% {
transform: scale(1.1);
}
}
#keyframes before {
0% {
transform: scale(1.0);
background: orange;
}
100% {
transform: scale(1.2);
background: red;
}
}
#keyframes explode {
0% {
transform: scale(1.0);
background: red;
opacity: 1;
}
100% {
transform: scale(2);
background: yellow;
opacity: 0;
}
}
#keyframes win {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
66% {
opacity: 1;
}
100% {
opacity: 0;
}
}
h4 {
font-family: sans-serif;
color: #333;
text-align: center;
}
p, strong {
font-family: sans-serif;
color: #333;
text-align: left;
font-size: 12px;
}
#win {
position: fixed;
left: 0;
right: 0;
top:0;
bottom: 0;
z-index: 9999999;
background: rgba(181, 181, 195, 0.1);
pointer-events: none;
opacity: 0;
}
#win p {
color: red;
font-size: 130px;
text-align: center;
font-family: sans-serif;
text-transform: uppercase;
height: 100%;
margin: 0;
top: 50%;
position: absolute;
left: 50%;
transform: translate(-50%, -25%);
right: 0;
bottom: 0;
font-weight: bold;
text-shadow: 5px 5px #333;
}
#win.show {
animation: win 4s ease;
}
#restart {
text-align: center;
padding: 10px 20px;
font-family: sans-serif;
color: #333;
outline: #ccc 1px solid;
display: table;
margin: auto;
margin-top: 20px;
cursor: pointer;
transition: 0.1s ease;
}
#restart:hover {
background: #eee;
}
<!DOCTYPE html>
<html>
<head>
<title>Bomberman</title>
<link href="bomber.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="1.js"></script>
</head>
<body>
<h4>Space bar to plant a bomb / Arrows to move </h4>
<div id="win"><p>WIN !</p></div>
<div id="restart"> RESTART </div>
<div id="score"><p>Score: </p><span>0</span><strong> / 0</strong></div>
<section id="game">
<div id="map">
<div id="player"></div>
</div>
</section>
</body>
</html>
I'm not certain I understand your question, but I think you're trying to debug the createTargets method in the Targets class. The problem there is an extra closing bracket (}) right before the line with //Show Total Targets.

Categories