I want to create a jQuery slime menu. The basic concept is simple. I have some icons with fixed positions on the screen. Some of them are "switches", and if you click them, you need to click on another element to have some effect (imageine something like when you have a building in an RTS. It's not enough to just click on the building's icon, but you need to place it on the map after that action).
I want to display a CSS triangle element after you clicked the icon, and before you click on another "compatible" div. The problem is not here, but I'm not so familiar with CSS transformations.
Here's a fiddle about what I have so far. My problem is that the arrow element is not rotating to the cursor. I also need to change the size of it, so the triangle's bottom center must be at the pointer.
http://jsfiddle.net/PSYKLON/41Lcj653/
The HTML part is simple (the span element is used for debugging):
<div class="fixicon"></div>
<div class="arrow"></div>
<span></span>
The CSS:
span {
float: right;
}
.fixicon {
width: 30px;
height: 30px;
background: #111;
border-radius: 15px;
position: fixed;
left: 10px;
top: 10px;
}
.arrow {
width: 0;
height: 0;
border-style: solid;
border-width: 0 25px 200px 25px;
border-color: transparent transparent #111 transparent;
opacity: 0;
position: fixed;
left: 0;
top: 25px;
transform-origin: 25px 0px;
transform: rotate(0deg);
}
.arrow.show {
opacity: 1;
}
And the JS:
$(function(){
$('.fixicon').click(function(){
$('.arrow').toggleClass('show');
});
$(window).mousemove(function(e){
if(!$('.arrow').hasClass('show')) {
return;
}
var dir = point_direction(25,25,e.pageX,e.pageY);
$('.arrow').css('transform','rotate('+dir+'deg)');
$('span').text(dir);
});
});
function point_direction(x1,y1,x2,y2) {
var dx,dy;
dy = y2 - y1;
dx = x2 - x1;
return (Math.atan(dy/dx) * 360) % 360;
}
So basically, I need to achieve something like this, doesn't matter where the cursor on the screen are:
Thanks for anyone, who can help. :)
Related
I have a project where I want a div to appear as a large box and three more to appear underneath as smaller boxes and when you click a smaller box, it switches sizes and places with the large box using css transitions to make the movement and size change smooth. Right now I'm attempting to use jQuery and the positioning is not working at all. Here's an example of what I have so far:
https://jsfiddle.net/v3pmhawj/1/
$(function () {
let { left: x1, top: y1 } = $('.full-size-card').offset()
$('.inactive-sheets .card').on('click', function() {
let { left: x2, top: y2 } = $(this).offset()
let curr = $('.full-size-card')
let diffX = x2 - x1
let diffY = y2 - y1
$(this).css({
left: -diffX,
top: -diffY
})
$(this).addClass('full-size-card')
curr.css({
left: diffX,
top: diffY
})
curr.removeClass('full-size-card')
})
})
If anyone has suggestions on ways that involve other libraries or other techniques, I'm all ears. I'd like to be able to move the divs around in the DOM as well but as far as I can tell, you can't css-transition them if you do that since the only way (I know of) is to delete and re-add a copy of the element where you want it in the DOM.
You can create animation effect using transitions only. To achieve this you will have to define width and height of your containers as well as top and left position of bottom elements.
On click, you just have to exchange classes of element that will become small and of element that will become large.
Here is fiddle of an example:
https://jsfiddle.net/fkd3ybwx/210/
HTML
<div class="card-container">
<div class="card large">A</div>
<div class="card small">B</div>
<div class="card small">C</div>
<div class="card small">D</div>
</div>
CSS
.card-container {
position: relative;
}
.card {
transition: all ease 1s;
position: absolute;
font-size: 24px;
border: white 4px solid;
box-sizing: border-box;
cursor: pointer;
}
.small {
width: 100px;
height: 100px;
background: blue;
left: 0;
top: 300px;
}
.small ~ .small {
left: 100px;
background: green;
}
.small ~ .small ~ .small {
left: 200px;
background: yellow;
}
.large {
width: 300px;
height: 300px;
background: red;
left: 0px;
top: 0px;
}
JavaScript
const smallCards = document.querySelectorAll('.card');
smallCards.forEach((smallCard) => {
smallCard.addEventListener('click', (event) => {
const largeCard = document.querySelector('.large');
largeCard.className = "card small";
event.target.className = "card large";
});
});
I am trying to make a div element which when scrolled down will change properties drastically. Here is the codepen example of how I want it to work.
Instead of hover I want it so that when scrolled down, the page wide div will turn into that little circle div which when clicked will function as a back to the top button. It doesn't matter if more classes are added or anything of that sort. I am very new to js and I tried a few things and also googled about it, I got the scroll code from w3school's how to make a back to top button guide which specifies that when scrolled down by 20px the code would react, but I don't know how to turn the JavaScript to JS when scrolled down along with the transformation of the div.
Thanks in advance
I think you want to implement scroll to top functionality, very common these days in most of the web app.
You need to keep below things and design that feature.
There is one header, that should have a reference ID with hash to scroll back to top
Create a button that will always static position (JS) button, will show up when user scroll the window
Bind click event on the button that scroll back to top
Here is the you can see this implementation and use it.
.html
<h1 class="intro-copy">
Scroll down to use this simple back-to-top button made with modern vanilla javascript.
</h1>
<a class="top-link hide" href="" id="js-top">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6"><path d="M12 6H0l6-6z"/></svg>
<span class="screen-reader-text">Back to top</span>
</a>
.css
body {
height: 2000px;
position: relative;
}
.intro-copy {
padding: 1em;
margin: 50vh auto;
max-width: 15em;
font-family: Helvetica;
font-weight: lighter;
font-size: 2em;
line-height: 1.2;
text-align: center;
}
.top-link {
transition: all .25s ease-in-out;
position: fixed;
bottom: 0;
right: 0;
display: inline-flex;
cursor: pointer;
align-items: center;
justify-content: center;
margin: 0 3em 3em 0;
border-radius: 50%;
padding: .25em;
width: 80px;
height: 80px;
background-color: #F8F8F8;
&.show {
visibility: visible;
opacity: 1;
}
&.hide {
visibility: hidden;
opacity: 0;
}
svg {
fill: #000;
width: 24px;
height: 12px;
}
&:hover {
background-color: #E8E8E8;
svg {
fill: #000000;
}
}
}
// Text meant only for screen readers.
.screen-reader-text {
position: absolute;
clip-path: inset(50%);
margin: -1px;
border: 0;
padding: 0;
width: 1px;
height: 1px;
overflow: hidden;
word-wrap: normal !important;
clip: rect(1px, 1px, 1px, 1px);
&:focus {
display: block;
top: 5px;
left: 5px;
z-index: 100000; // Above WP toolbar
clip-path: none;
background-color: #eee;
padding: 15px 23px 14px;
width: auto;
height: auto;
text-decoration: none;
line-height: normal;
color: #444;
font-size: 1em;
clip: auto !important;
}
}
JS:
// Set a variable for our button element.
const scrollToTopButton = document.getElementById('js-top');
// Let's set up a function that shows our scroll-to-top button if we scroll beyond the height of the initial window.
const scrollFunc = () => {
// Get the current scroll value
let y = window.scrollY;
// If the scroll value is greater than the window height, let's add a class to the scroll-to-top button to show it!
if (y > 0) {
scrollToTopButton.className = "top-link show";
} else {
scrollToTopButton.className = "top-link hide";
}
};
window.addEventListener("scroll", scrollFunc);
const scrollToTop = () => {
// Let's set a variable for the number of pixels we are from the top of the document.
const c = document.documentElement.scrollTop || document.body.scrollTop;
// If that number is greater than 0, we'll scroll back to 0, or the top of the document.
// We'll also animate that scroll with requestAnimationFrame:
// https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
// ScrollTo takes an x and a y coordinate.
// Increase the '10' value to get a smoother/slower scroll!
window.scrollTo(0, c - c / 10);
}
};
// When the button is clicked, run our ScrolltoTop function above!
scrollToTopButton.onclick = function(e) {
e.preventDefault();
scrollToTop();
}
I have a somewhat strange behaviour in Chrome and Safari. I have a scaled (transform: scale()) container with a video and other elements inside of it. At some scalings the absolute positioned elements with a high z-index disappears and does not come back again.
How can I fix this?
Note that I cannot give the video element a negative z-index and I need to use overflow: hidden;.
Example
I have made an example that scales the outermost container up and down. At a specifik scale value the element with class .on-top (and text "I should always be on top.") disappears. When scaling down again it suddenly appears.
Link to exmaple: https://jsfiddle.net/iafiawik/Lcox1ecc/
Conclusions
It seems like the size of the element matters. The larger I make it, the larger is the scale value before it disappears.
I have also tested to set transform: scale(1.4) with CSS directly on the element and the behaviour is the same.
The issue does not exist if I:
Replace the video tag with a div
Remove position: absolute; from siblings to .on-top (that is, .below)
Remove overflow: hidden; from .content
If I move .on-top so it is placed after the video tag in the document flow
(But of course none of these workarounds work for me in reality because of project specific reasons. I also cannot give the video element a negative z-index and I need to use overflow: hidden;.)
Suggested workarounds from the community (thanks!)
Give the video tag a negative z-index (can't do this because I sometimes have elements placed behind the video)
Remove overflow: hidden; (I can't remove overflow: hidden;)
Browsers
I have seen this issue in Chrome (Mac) and Safari (Mac).
Update 1
Seems like this bug report pretty much covers my problem. However, it does not provide a fix for it.
Update 2
I've answered my own question by providing my solution to this problem.
Update 3
There are a lot of answers coming in that either modify the z-index of the video or adds translateZ to the .on-top element. Demos have shown that both of those approaches do fix the issue.
However, since my HTML structure is the output from a visual HTML editor (long story ...), I do not know what elements will be there or if they should be in front, below or next to a video. Therefore I am looking for a solution that does not require changes to individual elements that are inside the scaled element.
It looks like a bug in Chrome. Notice that when you scale the image, the element inspector keeps telling you that the size of #scaled is 1024x768:
Where as in Firefox:
Now, apparently, Chrome uses the wrong size to conclude that .on-top is completely outside .content and hides it because of hidden overflow (it should not be doing this but apparently it is trying to optimize away any element that displays above a video). Examples:
Scale: 1.225
Parent width: 1254.40
Child left: 1254.40 - (100 + 90) * 1.225 = 1021.65
Result: less than 1024 (partially inside)
Scale: 1.230
Parent width: 1259.52
Child left: 1259.52 - (100 + 90) * 1.230 = 1025.82
Result: greater than 1024 (completely outside)
Unfortunately I could not find an elegant solution. Ideally you should revise your HTML markup and CSS, perhaps align the top element with left edge. As a last resort, you can move the elements more towards left using transparent border:
var goalScale = 140;
var startScale = 100;
var currentScale = 100;
var shouldScaleUp = true;
var container = document.getElementById("scaled");
var scaleInfo = document.getElementById("scale-info");
function step() {
container.style.transform = "scale(" + (currentScale / 100) + ")";
scaleInfo.innerText = "Scale: " + (currentScale / 100);
if (currentScale === goalScale) {
shouldScaleUp = false;
}
if (currentScale === startScale) {
shouldScaleUp = true;
}
if (shouldScaleUp) {
currentScale += 0.5;
} else {
currentScale -= 0.5;
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
.scale-info {
position: fixed;
left: 0;
top: 0;
}
#scaled {
background: #cccccc;
width: 1024px;
height: 768px;
position: fixed;
left: 200px;
top: 200px;
}
.content {
height: 100%;
overflow: hidden;
position: relative;
margin-left: auto;
margin-right: auto;
background: rgba(34, 34, 56, 0.2);
}
.below {
position: absolute;
width: 300px;
height: 300px;
right: 0px;
top: 100px;
background: purple;
z-index: 1;
opacity: 0.8;
}
.below-2 {
z-index: 3;
right: 100px;
}
.below-3 {
z-index: 4;
right: 400px;
}
.on-top {
position: absolute;
width: 50px;
right: 100px;
top: 150px;
background: pink;
z-index: 5;
padding: 20px;
/* a 200px border moves the element towards left */
border-left: 200px solid transparent;
background-clip: padding-box;
}
.on-top h1 {
font-size: 20px;
}
#video {
position: absolute;
z-index: 4;
width: 1024px;
height: 768px;
background: rgba(0, 0, 0, 0.4);
}
<div id="scale-info"></div>
<div id="scaled">
<div class="content">
<h2 class="below below-1"> I have z-index 1</h2>
<div class="on-top">
<h1> I should always be on top.<br> I have z-index 5</h1>
</div>
<h2 class="below below-2"> I have z-index 3</h2> <video id="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
<h2 class="below below-3"> I have z-index 4</h2>
</div>
</div>
Here you go: https://jsfiddle.net/Lcox1ecc/423/
You just need to add -webkit-transform: translateZ(0); to the .on-top class.
Happy Coding!
After spending a lot of time researching this problem and trying a lot of different approaches I've come to the conclusion that no solution fixes my problem. There are solutions that fix the problem if you are able to control the z-indexes of the elements that disappear, but I am unable to do so since the structure of the HTML is not known to be (it is the output of the HTML editor). I was looking for a solution that would not require changes to individual children to the scaled parent, but I have not found any so far.
This bug report pretty much covers my problem but it does not provide a fix for it.
I can confirm that this happens because the element is outside of the scaled containers original width and height:
The element is visible at scale(1.227) (red border indicates the original size of #scaled):
... but not at scale(1.228):
My solution is therefore to add another wrapping element outside the scaled element that is not scaled, but get its width and height properties updated according to its first child scale values. This element has overflow: hidden; and prevents elements from being visible.
This is not a perfect solution as one might experience a small gap between the scaled element and the outermost wrapping element (rounding issues), but it is the best I can do given the circumstances.
var goalScale = 140;
var startScale = 100;
var currentScale = 100;
var shouldScaleUp = true;
var container = document.getElementById("scaled");
var scaledContainer = document.getElementById("resized-container");
var scaleInfo = document.getElementById("scale-info");
function step() {
var contentWidth = 1024;
var contentHeight = 768;
container.style.transform = "scale(" + (currentScale / 100) + ")";
scaledContainer.style.width = contentWidth * ((currentScale / 100)) + "px";
scaledContainer.style.height = contentHeight * ((currentScale / 100)) + "px";
scaleInfo.innerText = "Scale: " + (currentScale / 100);
if (currentScale === goalScale) {
shouldScaleUp = false;
}
if (currentScale === startScale) {
shouldScaleUp = true;
}
if (shouldScaleUp) {
currentScale += 0.5;
} else {
currentScale -= 0.5;
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
#resized-container {
position: fixed;
width: 1024px;
height: 768px;
overflow: hidden;
border: 10px solid red;
top: 200px;
left: 200px;
}
#scaled {
background: #cccccc;
width: 1024px;
height: 768px;
position: absolute;
transform-origin: left top;
}
.content {
height: 100%;
position: relative;
margin-left: auto;
margin-right: auto;
background: rgba(34, 34, 56, 0.2);
}
.below {
position: absolute;
width: 300px;
height: 300px;
right: 0px;
top: 100px;
background: purple;
z-index: 1;
opacity: 0.8;
}
.below-2 {
z-index: 3;
right: 100px;
}
.below-3 {
z-index: 4;
right: 400px;
}
.on-top {
position: absolute;
width: 50px;
right: -30px;
top: 150px;
background: pink;
z-index: 5;
padding: 20px;
}
.on-top h1 {
font-size: 20px;
}
#video {
position: absolute;
z-index: 4;
width: 1024px;
height: 768px;
background: rgba(0, 0, 0, 0.4);
}
<div id="resized-container">
<div id="scaled">
<div id="scale-info">
</div>
<div class="content">
<h2 class="below below-1">
I have z-index 1
</h2>
<div class="on-top">
<h1>
I should always be on top.<br /> I have z-index 5
</h1>
</div>
<h2 class="below below-2">
I have z-index 3
</h2>
<video id="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
<h2 class="below below-3">
I have z-index 4
</h2>
</div>
</div>
</div>
One approach, if you can modify a bit your html, is wrap your problematic elements in a container that is the same size as the video and container, with the proper z-index. That way you would have clear layers of the same size and positions, into which you can position more complex elements. Like this for example:
<div id="top-container">
<div class="on-top">
<h1>
I should always be on top.<br /> I have z-index 5
</h1>
</div>
</div>
#top-container {
width: 100%;
height: 100%;
position: absolute;
z-index: 5;
}
https://jsfiddle.net/06oykj8o/4/
I made this workaround by puttingz-index:-1; on video.
https://jsfiddle.net/Lcox1ecc/312/
I really like the answer from Salman A.
The only thing that comes to mind, would be rewriting with position: relative.
But I don't know if that is an option.
I stumbled across something similar to this last week with positioning absolute elements and transforms...
I dunno if this will help you out but here is a link.
CSS transform: translate moves postion:fixed inner Div
In the end I fixed it by using a transform: translateX(none) vs translateX(0).
Super strange behavior for sure, but the link gives some more links to help make things more clear - as in its behaving per spec.
It is happening because of overflow is hidden.Here is working link
https://jsfiddle.net/Lcox1ecc/322/
.content {
overflow:visible;
}
It might be late but just posting in case somebody finds it helpful.
Add an empty div under the parent container element with transform animation and nothing will disappear anymore. The animation does not do anything but it forces the browser to render all the elements using hardware acceleration.
<div class="emptydiv"></div>
.emptydiv{
transform:scale(1);
animation:fix 3s infinite;
}
#keyframes fix{
50%{
transform:scale(1);
}
}
I am pretty new to jQuery and I am having a bit of difficulty adapting to it being a Java nerd.
I am trying to make these 3 boxes so that when you click one of them, it comes forward and the two in the back dim and stay there, in the back. The problem is that, I want to make it so when you click more than 1 box consecutively, the second box clicked doesn't come forward until the animation ends, much like a queue of box clicks. Right now it's all mixed up and the dimming is fine but the boxes come forward as soon as I click them and not when they should.
I tried callbacks and deferred to no avail.
Here is the code:
Javascript:
var zindex = 1;
$('.box_listener').click(function() {
$(this).css('z-index', zindex += 1);
$(this).siblings('.box_listener').fadeTo(3000, 0.5);
$(this).fadeTo(1, 1);
});
Here is the JSFiddle:
https://jsfiddle.net/asger/5yvvgoda/14/
var zindex = 1;
$('.box_listener').click(function() {
$(this).css('z-index', zindex += 1);
$(this).siblings('.box_listener').fadeTo(3000, 0.5);
$(this).fadeTo(1, 1);
});
#backgroundbox {
position: absolute;
width: 400px;
height: 200px;
background-color: #E5E8E8;
z-index: -5;
border-style: solid;
border-width: 1px;
}
.box_listener {
position: absolute;
width: 120px;
height: 120px;
background-color: white;
border-style: solid;
border-width: 1px;
}
#redbox {
left: 270px;
top: 20px;
border-color: red;
z-index: 0;
}
#bluebox {
left: 230px;
top: 60px;
border-color: blue;
z-index: 0;
}
#greenbox {
left: 210px;
top: 77px;
border-color: lightgreen;
z-index: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="backgroundbox">
<div class="box_listener" id="redbox">
</div>
<div class="box_listener" id="bluebox">
</div>
<div class="box_listener" id="greenbox">
</div>
</div>
Cheers and thanks!
A more bulletproof approach is to not use jQuery animations at all and instead use CSS transitions. The reason for this is twofold; CSS transitions can be automatically reversed and they can be GPU accelerated. It also means you don't have to artificially wait for the transition to complete before allowing user input.
To accomplish this, just set up two CSS classes; One that tells the elements you're going to animate how they should transition. The other class changes the values on the element, which causes the transition to happen. Then all jQuery needs to do is addClass() and removeClass() in order to cause the transitions to occur.
Below is an example of it in action. I've highlighted the most important aspects with comments.
$('.btn').on('click', function() {
// remove the active class from all buttons,
// this will reverse the transition
$('.btn').removeClass('active');
// apply it to only the current button clicked,
//this will start the transition
$(this).addClass('active');
});
.btn {
display: block;
width: 200px;
padding: 10px 20px;
margin-bottom: 5px;
background: cornflowerblue;
border: 0;
cursor: pointer;
/* set up a transition on any css transformations like
translating, scaling, rotating, etc. */
transition: transform 300ms ease-in-out;
}
/* when this class is added to the button it will scale it, but the
transition already on the button will make sure it happens slowly */
.active {
transform: scale(1.2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Click the buttons</h2>
<button class="btn">First</button>
<button class="btn">Second</button>
<button class="btn">Third</button>
Image
ul#listcontainer .li1 {
display: block;
width: 210px;
height: 130px;
border: 1px solid red;
position: relative;
}
.li1 span {
position: absolute;
top: 140px;
left: 0px;
right: 0;
width: 220px;
padding: 2px 0;
background-color: #000;
background-color: rgba(0, 0, 0, 0.65);
color: #fff;
opacity: 0;
transition: opacity .5s ease-in-out;
text-align: center;
font-family: Arial;
font-size: 14px;
}
.li1:hover span {
opacity: 1;
}
.li1:hover span:hover {
opacity: 0;
}
<ul id="listcontainer">
<li class="li1">
<img src="images/li1.png"><span><b>Exteriors:</b> <br>Minimal Wear, Battle Scarred<br><br><img src="images/tick.png"><br> </span>
</li>
</ul>
Hello everyone. So I made a tooltip showing after I hover the box with red border. The thing I want is that when I hover over the div with red border - the tooltip begin to moving/following with the mouse. Tried to search how to do it but I didn't found answer. I think it will be some jQuery code... I let you guys tell me. Thanks.
Try this code and no need to change the css as shown in this http://jsfiddle.net/bo113jxu/8/ :
$('.li1').mousemove(function (e) {
$('span', this).css({left: e.pageX - 100, top: e.pageY + 10});
});
EDIT:
The position:absolute will work good as long as there's only one .li1 element, but in case we have more .li1 elements we'd face a problem shown in this jsfiddle demo1; TO fix this the position of .li1 should be set to fixed jsfiddle demo2.. just like what #ViktorMaksimov kudos said in his answer which I was wrong about it.
CSS code:
.li1 span {
position: fixed;
margin-left: -110px;
}
jQuery code:
$(document).ready(function() {
$('.li1').mousemove(function( event ) {
$(this).find('span').css({ //Position the tooltip
'left' : event.pageX + 'px', //Left position - the X position of the mouse
"top" : (event.pageY + 20) + 'px' //Top position - the Y position of the mouse
});
});
});
Firstly the tooltip should be positioned fixed.
When you are moving the mouse inside the <li> element the tooltip will have left position - the position on X of the mouse to the window, and top position the position on Y of the mouse + 20, because the tooltip not to be exactly next to the mouse, because if you move your mouse fast enough the tooltip will hide.
And we are setting margin-left to the tooltip - negative value half of its width to make the tooltip centered to the mouse.