I want to create animations on buttons in Javascript. When I hover any buttons animations must follow cursor for now I create working sample with one buttons here: https://jsfiddle.net/sL0uebh4/
const btn = document.querySelector('.btn');
btn.onmousemove = function(e) {
const x = e.pageX - btn.offsetLeft;
const y = e.pageY - btn.offsetTop;
btn.style.setProperty('--x', x + 'px')
btn.style.setProperty('--y', y + 'px')
}
.btn {
display: block;
width: 150px;
height: 50px;
background: #666;
margin: 10px;
}
.btn::before {
content: '';
position: absolute;
top: var(--y);
left: var(--x);
width: 0;
height: 0;
background: #ff0000;
}
.btn:hover::before {
width: 30px;
height: 30px;
}
<a href#="" class="btn">Click</a>
<a href#="" class="btn">Click2</a>
<a href#="" class="btn">Click3</a>
I know I need change querySelector() to querySelectorAll and in my code use somehow forEach() but all my attempts failed and I need a little hint how it should looks.
<a href#="" onmousemove="animation(this.id)" id="btn1" class="btn">
Click
</a>
<a href#="" onmousemove="animation(this.id)" id="btn2"class="btn">
Click2
</a>
<a href#="" onmousemove="animation(this.id)" id="btn3" class="btn">
Click3
</a>
JavaScript:
function animation(id){
const btn = document.getElementById(id)
console.log(btn)
btn.onmousemove = function(e) {
const x = e.pageX;
const y = e.pageY;
btn.style.setProperty('--x', x + 'px')
btn.style.setProperty('--y', y + 'px')
}
}
Related
I am trying to implement a drag and drop functionality using vanilla Javascript on my web app, where element gets moved to a new position within a div, once it's dragged and dropped.
But I am having an issue where I can drop the element fine the first time, but I can no longer do it the second time onwards.
After debugging, I have noticed that the first time I drop an element, it does not have any inline style (see Appendix A). But when I try and do it the second time, it now has an inline style (see Appendix B) and for some reason, I cannot chnage the values of it. That was also the case after I manually added inline style to my draggable element- I could not drop the item even the first time when I did it.
I am completely out of ideas as to what I could be doing wrong and no similar questions yielded a solution.
Thank you very much in advance for your time.
Code (Unnecessary parts ommitted)
const list = document.querySelector("#list");
const rect = list.getBoundingClientRect();
let oldLeft, oldTop, mouseXStart, mouseYStart;
function dragStart(event) {
event.dataTransfer.setData("plain/text", event.target.id);
const item = document.querySelector("#" + event.target.id);
mouseXStart = event.clientX - rect.left;
mouseYStart = event.clientY - rect.top;
oldLeft = item.style.left;
oldTop = item.style.top;
console.log(item);
}
function dragOver(event) {
event.preventDefault();
event.dataTransfer.dropEffect = "move";
}
function dropItem(event) {
event.preventDefault();
const mouseXEnd = event.clientX - rect.left;
const mouseYEnd = event.clientY - rect.top;
//Calculate by how much mouse has been moved
const newLeft = mouseXEnd - mouseXStart;
const newTop = mouseYEnd - mouseYStart;
const item = document.querySelector('#' + event.dataTransfer.getData("plain/text"));
item.style.left = oldLeft + newLeft + "px";
item.style.top = oldTop + newTop + "px";
}
#list {
position: relative;
top: 60px;
height: 600px;
width: 100%;
border: 2px solid rgb(107, 14, 14);
display: block;
}
#list>div {
position: absolute;
height: 200px;
width: 200px;
background-color: blue;
margin: 10px;
overflow: hidden;
text-align: left;
}
<div id="list" ondrop="dropItem(event)" ondragover="dragOver(event)">
<div id="test" draggable="true" ondragstart="dragStart(event)">
<button type="button"></button>
<div>
<p>Test</p>
</div>
</div>
</div>
Appendix A
console.log() output on the first dragStart() call:
<div id="test" draggable="true" ondragstart="dragStart(event)">
Appendix B
console.log() output on the second dragStart() call:
<div id="test" draggable="true" ondragstart="dragStart(event)" style="left: 853px; top: 147px;">
Problem
This code
oldLeft + newLeft + "px"
evaluated to something like
123px40px
because
oldLeft = item.style.left
returned string with px at the end
Solution
Parse the value to float
oldLeft = item.style.left ? parseFloat(item.style.left) : 0;
oldTop = item.style.top ? parseFloat(item.style.top) : 0;
const list = document.querySelector("#list");
const rect = list.getBoundingClientRect();
let oldLeft, oldTop, mouseXStart, mouseYStart;
function dragStart(event) {
event.dataTransfer.setData("plain/text", event.target.id);
const item = document.querySelector("#" + event.target.id);
mouseXStart = event.clientX - rect.left;
mouseYStart = event.clientY - rect.top;
oldLeft = item.style.left ? parseFloat(item.style.left) : 0;
oldTop = item.style.top ? parseFloat(item.style.top) : 0;
}
function dragOver(event) {
event.preventDefault();
event.dataTransfer.dropEffect = "move";
}
function dropItem(event) {
event.preventDefault();
const mouseXEnd = event.clientX - rect.left;
const mouseYEnd = event.clientY - rect.top;
//Calculate by how much mouse has been moved
const newLeft = mouseXEnd - mouseXStart;
const newTop = mouseYEnd - mouseYStart;
const item = document.querySelector('#' + event.dataTransfer.getData("plain/text"));
item.style.left = oldLeft + newLeft + "px";
item.style.top = oldTop + newTop + "px";
}
#list {
position: relative;
top: 60px;
height: 600px;
width: 100%;
border: 2px solid rgb(107, 14, 14);
display: block;
}
#list>div {
position: absolute;
height: 200px;
width: 200px;
background-color: blue;
margin: 10px;
overflow: hidden;
text-align: left;
}
<div id="list" ondrop="dropItem(event)" ondragover="dragOver(event)">
<div id="test" draggable="true" ondragstart="dragStart(event)">
<button type="button"></button>
<div>
<p>Test</p>
</div>
</div>
</div>
When I click on the button, I would like the position of the button to change to a random location.
Here is what I have tried:
var b = document.querySelector("button");
b.addEventListener("click",change);
var i = Math.floor(Math.random()*500)+1;
var j = Math.floor(Math.random()*500)+1;
function change()
{
b.style.left = i+"px";
b.style.top = j+"px";
}
button{
margin-left: auto;
margin-right: auto;
display: block;
position: absoulte;
}
<button>
Hello World
</button>
Define i and j inside change() method so that it can be randomly updated when button is clicked.
Also, there is a typo in your code position: absoulte which should be corrected to absolute
var b = document.querySelector("button");
b.addEventListener("click",change);
function change()
{
var i = Math.floor(Math.random()*500)+1;
var j = Math.floor(Math.random()*500)+1;
b.style.left = i+"px";
b.style.top = j+"px";
}
button{
display: block;
position: absolute;
}
<button>abc</button>
HTML :-
<body>
<div class="ctr">
<button class="button" id="movingbutton">Button</button>
</div>
</body>
CSS:-
#movingbutton{
margin-left: auto;
margin-right: auto;
display: block;
position: absolute;
left : 20px;
top : 50px;
}
body{
width : 100%;
}
.ctr{
width : 100%;
height : 100%;
}
JS:-
var b = document.querySelector("#movingbutton");
b.addEventListener("click",change);
function change()
{
let i =Math.abs(Math.floor(Math.random()*window.innerWidth-55))
let j = Math.abs(Math.floor(Math.random()*window.innerHeight-21));
console.log('here' , i ,j , b.style.left , b.style.top);
b.style.left = i+'px';
b.style.top = j + "px";
}
If you want you can check here: Live example link
You need to add one more condition if that button goes outside window.innerWidth and window.innerHeight
You'll need to move the random calculation inside the change() function.
To keep the element within it's containing element you can use getBoundingClientRect(). (And account for the size of the button to avoid overlaps on the right and bottom using the same.)
const c = document.querySelector(".container");
const b = document.querySelector("button");
function change() {
const
{ width: cWidth, height: cHeight } = c.getBoundingClientRect(),
{ width: bWidth, height: bHeight } = b.getBoundingClientRect(),
i = Math.floor(Math.random() * (cWidth - bWidth)) + 1,
j = Math.floor(Math.random() * (cHeight - bHeight)) + 1;
b.style.left = i + "px";
b.style.top = j + "px";
}
b.addEventListener("click", change);
.container {
position: relative;
height: 50vh;
width: 50vw;
background-color: lightgray;
}
button{
position: absolute;
display: block;
}
<div class='container'>
<button type='button' id='shifty'>Click</button>
</div>
If you want to move randomly a button you can use simple .bind(). You can also move button when your mouse is moving in button area(without clicking it) .
Here are both codes:
Code for click
var b = document.querySelector("#movingbutton");
b.addEventListener("click",change);
function change()
{
let i = Math.floor(Math.random()*500)+1;
let j = Math.floor(Math.random()*500)+1;
console.log('here' , i ,j , b.style.left , b.style.top);
b.style.left = i+'px';
b.style.top = j + "px";
}
#movingbutton{
margin-left: auto;
margin-right: auto;
display: block;
position: absolute;
left : 20px;
top : 50px;
}
body{
width : 100%;
}
.ctr{
width : 100%;
height : 100%;
}
<body>
<div class="ctr">
<button class="button" id="movingbutton">Button</button>
</div>
</body>
Code for mousemove
var b = document.querySelector("#movingbutton");
b.addEventListener("mousemove",change);
function change()
{
let i = Math.floor(Math.random()*500)+1;
let j = Math.floor(Math.random()*500)+1;
console.log('here' , i ,j , b.style.left , b.style.top);
b.style.left = i+'px';
b.style.top = j + "px";
}
#movingbutton{
margin-left: auto;
margin-right: auto;
display: block;
position: absolute;
left : 20px;
top : 50px;
}
body{
width : 100%;
}
.ctr{
width : 100%;
height : 100%;
}
<body>
<div class="ctr">
<button class="button" id="movingbutton">Button</button>
</div>
</body>
I am getting the correct position of the element if I click using mouse, but not able to get if click through tab key.
To reproduce the behavior, focus on the element using tab and press Enter.
var linkElement = document.getElementById('link');
linkElement.addEventListener('click', function(e){
console.log(e.clientX, e.clientY);
});
#link{
position: absolute;
top: 5%;
left: 15%;
}
#placeholder{
display: none;
background: rgba(0, 0, 0, 0.4);
}
<a href="javascript:void(0)" id="link">
LINK
</a>
<div id="placeholder">
PLACEHOLDER
</div>
It seems that clientX and clientY is only for the mouse according to this.
What I would do is to return the coords of the center on tab by the offset properties (when the clientX and the clientY are 0,0):
var linkElement = document.getElementById('link');
linkElement.addEventListener('click', function(e){
if (e.clientX > 0 && e.clientY > 0) {
console.log(e.clientX, e.clientY);
} else {
console.log(this.offsetLeft + (this.offsetWidth / 2), this.offsetTop + (this.offsetHeight / 2));
}
});
#link{
position: absolute;
top: 5%;
left: 15%;
}
#placeholder{
display: none;
background: rgba(0, 0, 0, 0.4);
}
<a href="javascript:void(0)" id="link">
LINK
</a>
<div id="placeholder">
PLACEHOLDER
</div>
UPDATE:
Or with getBoundingRect as epascarello suggested:
var linkElement = document.getElementById('link');
linkElement.addEventListener('click', function(e){
if (e.clientX > 0 && e.clientY > 0) {
console.log(e.clientX, e.clientY);
} else {
var boundingRect = this.getBoundingClientRect();
console.log(Math.round(boundingRect.x + (boundingRect.width / 2)), Math.round(boundingRect.y + (boundingRect.height / 2)));
}
});
#link{
position: absolute;
top: 5%;
left: 15%;
}
#placeholder{
display: none;
background: rgba(0, 0, 0, 0.4);
}
<a href="javascript:void(0)" id="link">
LINK
</a>
<div id="placeholder">
PLACEHOLDER
</div>
I'm trying to do exactly as it is in this link.
(The stripe on the banners with the read more link)
https://toyota.jp/vitz
What I tried so far doesn't work as expected. It moves the whole stripe apart from the range.
$(document).on("click mousemove", ".spec-slider-wrap", function(e) {
var x = e.clientX;
var y = e.clientY;
var newposX = x - 700;
var newposY = y - 350;
$(".stripe").css("transform", "translate3d(" + newposX + "px," + newposY + "px,0px)");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<span class="word">More</span>
<span class="arrow-wrap">
<span class="arrow-pulse-right"></span>
</span>
</div>
here the working code.
https://jsbin.com/geyudivuru/edit?html,css,js,output
<div class="parent" style="">
<div class="stripe">
<span class="word">More</span>
<span class="arrow-wrap">
<span class="arrow-pulse-right"></span>
</span>
<div>
</div>
.stripe {
width: 100%;
background: red;
position: absolute;
height: 40px;
display: none;
}
.parent {
position: relative;
height: 400px;
background: #ddd;
}
$ = jQuery;
$(document).on("mousemove", function(e) {
var x = e.clientX;
var y = e.clientY;
var newposX = x - 700;
var newposY = y;
$('.stripe').css({top: newposY, display: 'block'})
});
$('.parent').mouseleave(function(){
$('.stripe').css({top: 0, display: 'none'})
})
add styling to divs and you'll get what you need.
So basically I'm creating a tooltip function.
And tooltip will appear as a new DOM element over the element you clicked.
Here is the fiddle:
$(document).ready(function () {
$('.tooltipTarget').click(function () {
var title = $(this).data('tooltip');
$('<p class="tooltip active"></p>')
.text(title)
.appendTo('body')
.fadeIn(250);
var coords = $(this).offset();
var tooltipHeight = $('.tooltip').height() + $(this).height() + 20;
var tooltipWidth = $('.tooltip').width() / 2;
coords.top = coords.top - tooltipHeight;
coords.left = coords.left - tooltipWidth;
$('.tooltip').css({
top: coords.top,
left: coords.left
});
});
});
.tooltip {
display: none;
position: absolute;
border-radius: 1px;
color: #767676;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
background: #f7f7f7;
padding: 10px;
font-size: 12px;
text-align: left;
z-index: 10;
max-width: 250px;
}
<button style="margin: 50px;" data-tooltip="This is a tooltip" class="tooltipTarget">Click me!</button>
But the problem I have is that new DOM elements will keep appearing as long as you trigger the event.
I wont to prevent it. I want it to be like this:
1)You click a button
2)Tooltip appears
3)You click again on the button - tooltip disappears.
How can I do it?
Working fiddle: https://jsfiddle.net/4d8xhLqj/2/
I would second what #JamesSutherland has put. The tooltip should pre-exist so you only have to play with its positioning and opacity later on.
Having said that though, if you really need to follow the approach that you already have, you could do this:
Snippet:
$(document).ready(function() {
$('.tooltipTarget').click(function() {
var title = $(this).data('tooltip');
if (!$('p.tooltip').hasClass('active')) {
$('<p class="tooltip active"></p>')
.text(title)
.appendTo('body')
.fadeIn(250);
var coords = $(this).offset();
var tooltipHeight = $('.tooltip').height() + $(this).height() + 20;
var tooltipWidth = $('.tooltip').width() / 2;
coords.top = coords.top - tooltipHeight;
coords.left = coords.left - tooltipWidth;
$('.tooltip').css({
top: coords.top,
left: coords.left
});
} else {
$('p.tooltip.active').fadeOut(250, function() {
$(this).remove();
});
}
});
});
.tooltip {
display: none;
position: absolute;
border-radius: 1px;
color: #767676;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
background: #f7f7f7;
padding: 10px;
font-size: 12px;
text-align: left;
z-index: 10;
max-width: 250px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button style="margin: 200px;" data-tooltip="This is a tooltip" class="tooltipTarget">Click me!</button>
Here is the resulting fiddle. Hope this helps.
You should check if the tooltip is already shown:
$(document).ready(function () {
$('.tooltipTarget').click(function () {
var title = $(this).data('tooltip');
if ($('.tooltip[data-title=' + title + ']').length > 0) {
$('.tooltip[data-title=' + title + ']').remove();
return;
}
$('<p class="tooltip active" data-title=" ' + title + ' "></p>')
.text(title)
.appendTo('body')
.fadeIn(250);
var coords = $(this).offset();
var tooltipHeight = $('.tooltip').height() + $(this).height() + 20;
var tooltipWidth = $('.tooltip').width() / 2;
coords.top = coords.top - tooltipHeight;
coords.left = coords.left - tooltipWidth;
$('.tooltip').css({
top: coords.top,
left: coords.left
});
});
});
I've added a data attribute to the newly created tooltip in order to check afterwards if there is a tooltip for that element present, and if yes, remove it and return.
just check whether or not the tooltip exists as part of your click function. Remove the tooltip when it does exist and create a tooltip when it doesn't.
if($('.tooltip').length) {
$('.tooltip').remove();
}
else {
//create the tooltip as usual here
}
here is a working fiddle
https://jsfiddle.net/4d8xhLqj/3/