I'm creating a 3D carousel using CSS and javascript. For testing and developing, I've uploaded what I have so far on this page: http://dev.rushfivedesigns.com/
When you get to the page, please hit the "initialize" button to have it transformed into 3D space. By default, it will initialize with 5 panels, and this can be changed using the controls.
The problem I'd like to solve is this: When I increase the number of panels, the distance from the origin increases and so the panels increase in perceptible size (they get blown up). I'd like it if the front panel would always retain the same size, regardless of how many panels there are.
So rather than pushing every panel out by x distance, I want the front panel to stay at a static location in 3D space, and then everything else is pushed around behind it (hope that makes sense).
I've made this using angular, but this could easily be made using plain javascript as well. Here's the relevant code:
HTML
<div id="musicPlayer">
<section class="container">
<div id="carousel">
<figure class="something" ng-repeat="item in items">item {{item.someKey}}</figure>
</div>
</section>
</div>
CSS
.container {
width:300px;
height:300px;
position:relative;
perspective: 1000px;
margin-left: 400px;
margin-top:100px;
}
#carousel {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
}
#carousel figure {
display: block;
position: absolute;
left: 10px;
top: 10px;
border: 2px solid black;
width: 276px;
height: 276px;
}
Javascript
$scope.items = [];
for (var i = 0; i < 5; i++) {
var filler = {
someKey: i
};
$scope.items.push(filler);
};
$scope.initializeCarousel = function () {
var carousel = document.getElementById('carousel');
var numPanels = $scope.items.length;
var theta = 360 / numPanels; // rotation between each panel in 3D space
var radius = Math.round(150 / Math.tan(Math.PI / numPanels)); // how far in Z-axis the panels are pushed out
//rotate panels by theta
for (var i = 0; i < $scope.items.length; i++) {
var panel = carousel.children[i];
var angle = theta * i;
panel.style.transform = 'rotateY(' + angle + 'deg) translateZ(' + radius + 'px)';
};
};
Everytime the "initialize" button is pressed, the $scope.initializeCarousel function is called, using the # of panels chosen.
I have a feeling this may just be related to CSS coding, and not necessarily the javascript, but I'm really not sure. I'm completely new to CSS animating.
Any guidance on this would be great. Thanks S.O.!
My guess is you need to figure out the radius of the "sphere" and move all the panels in the z direction at least that distance forward. The better way to do it would be by moving the camera which is where you are positioned away from the object.
Related
I'm creating an Electron program that loops a video comprising of adverts. The video spans the entire window. Let's call this window A.
There is a second, smaller window used to configure aspects of window A. Let's call this window B.
The purpose of window B is to control aspects of window A in real time, such as overlaying a message over the video or hiding the video controls. Here's an image to explain further:
Seen in the photo above, there is a further window open displaying a smaller video. Let's call this window C. The blue rectangle can be dragged around and represents a message that will be display over the video on window A.
If I save the coordinates of that rectangle and create an element on the window A video, the coordinates don't match up due to the difference in window sizes. What I can't figure out is how to take the coordinates in window C and apply them to window A correctly. I've tried working with clientWidth/clientHeight and messing with numerous CodePen's to no avail.
Any help would be greatly appreciated.
Each pixel in the smaller div equals X pixels in the bigger div. That's the ratio to multiply with. Let's assume mouse movement inside smaller div is like dragging and affecting the bigger div.
var small = document.querySelector(".small");
var big = document.querySelector(".big");
var rectangle = document.querySelector(".rectangle");
var ratioX = big.clientWidth / small.clientWidth
var ratioY = big.clientHeight / small.clientHeight
small.addEventListener("mousemove", function(ev) {
var mx = ev.offsetX
var my = ev.offsetY
rectangle.style.left = mx * ratioX + "px"
rectangle.style.top = my * ratioY + "px"
})
.small {
width: 100px;
height: 50px;
border: 1px solid black;
}
.big {
width: 300px;
height: 150px;
border: 1px solid black;
position: relative;
overflow: hidden;
}
.rectangle {
width: 20px;
height: 20px;
background: blue;
position: absolute;
}
Mouse over this:
<div class="small">
</div>
Will move this:
<div class="big">
<div class="rectangle">
</div>
</div>
I've just revamped my tooltip code due to issues with the position altering depending on the size of it's parent (mostly due to using offsetX/Y instead of pageX/Y, but page was being weird, too). So I decided to just have one tooltip for each of my site's pages, parented to the main div, and just feed it different text depending on what the mouse is hovering over (I'll be dealing with the visibility part later).
And it's worked quite well so far, but the only issue is that, the smaller I make my window, the farther the tooltip is from my mouse, until it's not even in view anymore.
Here's the JavaScript coding I've done for it.
var body = document.getElementsByClassName("test");
var tooltip = document.getElementById("tooltip");
body[0].addEventListener("mousemove", tooltipMove)
function tooltipMove(event) {
var x = event.pageX;
var y = event.pageY;
tooltip.style.top = (y + -900) + "px";
tooltip.style.left = (x + -875) + "px";
}
The CSS coding for the tooltip:
.tooltip {
visibility: hidden;
width: 170px;
background-color: white;
background-image: url("images/tooltipbackground.png");
color: black;
text-align: center;
border-style: groove;
border-color: #f4bb4c #ffd966 #ffd966 #f4bb4c;
border-radius: 2px;
padding: 5px 5px;
position: absolute;
z-index: 1;
}
.notfound:hover .tooltip {
visibility: visible;
}
And the HTML:
<div class="test" style="top: 70px; position: relative; height: 100%; width: 100%;">
<h1>TEST</h1>
<img src="images/pagenotfound.png">
</div>
<div style="width: 1px; height: 1px; position: relative;">
<span class="tooltip" id="tooltip">testing</span>
</div>
I should mention the body's (which has the "notfound" class) height is 900px, and it's width 600px, in case that's one of the problems.
The 1 pixel div is just what I'm using to "host" the tooltip, not sure if it's causing any problems as well. I inspected the page in order to see it, and it never seemed to slide around with the window size.
Any sort of help would be greatly appreciated. I've tried to switch it from pageX/Y to clientX/Y, but it's the same issue. And using offset causes it's position to shift depending on what I'm hovering over, which is the reason I'm revamping the code in the first place.
I've also tried to change the tooltip's position from absolute to, well, anything else (after resizing it's parent so it doesn't get squashed), but that hasn't helped.
Another thing I should mention is that, for some reason, the shifting doesn't seem to happen in the Y axis, it's only when I squish the window horizontally that the tooltip shifts, at least from what I've noticed.
I had thought changing the tooltip's position to fixed had made it disappear, but I just couldn't see it due to the massive repositioning I had done to it. Once I deleted that it was visible and fine, and better yet, it stays in it's proper position no matter the screen size!
Also note: I had to change pageX/Y to clientX/Y, as using page made the tooltip shift vertically when squished.
<div style="height: 1px; width: 1px; position: relative;">
<span class="tooltip" id="tooltip" style="position: fixed;">Placeholder</span>
</div>
for (i = 0; i < tip.length; i++) {
tip[i].addEventListener("mousemove", tooltipMove)
tip[i].addEventListener("mouseleave", defaultVis)
}
function tooltipMove(event) {
var x = event.clientX;
var y = event.clientY;
tooltip.style.visibility = "visible";
tooltip.style.top = (y + -50) + "px";
tooltip.style.left = (x + -200) + "px";
}
function defaultVis() {
tooltip.style.visibility = "hidden";
}
I am trying to create an eye that follows cursor movement.
I got the horizontal and vertical coordinate of the mouse and the browser width and height.
Everything works perfectly. Except that I used rotate(45 deg) on the design of the eye so now the ball is not moving in the right position.
I was thinking about a math equation that finds the distance between the old and new coords, but I am not sure how to implement it.
Here is the full code:
https://jsfiddle.net/Mr_MeS/3ym6kuec/3/
so this is the .eye where its rotated
.eye {
width: 37.5px;
height: 37.5px;
background: white;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
border-radius: 75% 0;
overflow: hidden;
cursor: pointer;
}
.ball {
width: 7.5px;
height: 7.5px;
background: #222f3e;
border-radius: 50%;
border: 5px solid #576574;
position: relative;
top: 50%;
left: 50%;
}
and here is the JS that does the work and needs to be edited.
var balls = document.getElementsByClassName("ball");
document.onmousemove = function () {
var x = event.clientX * 100 / window.innerWidth + "%";
var y = event.clientY * 100 / window.innerHeight + "%";
//event.clientX => get the horizontal coordinate of the mouse
//event.clientY => get the Vertical coordinate of the mouse
//window.innerWidth => get the browser width
//window.innerHeight => get the browser height
for (var i = 0; i < 2; i++) {
balls[0].style.left = x;
balls[0].style.top = y;
balls[0].style.transform = "translate(-" + x + ",-" + y + ")";
}
}
Now, if I remove the rotation from the .eye, it works perfectly, expect that the whole shape doesn't look to be in position.
If I keep the 45deg rotation, the shape is good, but the ball moves wrongly.
You could try to put the eye-background (the white part that needs to rotate 45 degrees) into a div (or pseudo-element) that's inside the .eye element. In that way you don't need to rotate the container element, so the coordination of the ball element stays the same.
Another point, why are you using that for-loop? I think running the code once will be sufficient :)
EDIT: I've been playing around with your example a bit and fixed it. What happens is that if you rotate an element, the direction in which things will transform (and top/left positioning) will also change. So moving the element 10px to the left, will go 10px to the left, under a 45 degree angle, because it's rotated 45 degrees.
What I did now was to put an element (.inner) inside the eye div, which I gave a counter-rotation of -45 degrees. In this way, the container element of the ball has the correct orientation again, which fixes the problem: https://jsfiddle.net/bxprjvgL/
HTML:
<div class="eye">
<div class="inner">
<div class="shut"><span></span></div>
<div class="ball"></div>
</div>
</div>
CSS:
.inner {
width: 100%;
height: 100%;
transform: rotate(-45deg);
}
I've been working on a scrolling effect for my site that has been driving me crazy, and it's probably not even worth it but I can't stop now.
I have been able to simulate the effect using adobe edge and muse. Can anyone think of a simpler method of creating this effect? The animation can be seen here. As you scroll, the header shape changes and resizes. I have tried doing this with svg animate, div rotation animate, etc. with no luck.
Any help would be appreciated.
Normally we don't provide full solutions for questions, but I had some free time and this was a pretty fun project. If my answer works for you I hope you'll accept it.
I'm sure there are more efficient ways to do this (manipulating an SVG for example), but I kept this as succinct as I possibly could. This is using CSS and Javascript / jQuery. I'll let the comments in the javascript portion do the explaining.
HTML
<div id="animation">
<div id="box"></div>
<div id="ang"></div>
</div>
CSS
#animation {
width: 500px;
position: fixed;
top: 0;
left: 50%;
margin-left: -250px;
}
#box {
width: 500px;
height: 125px;
background: #333;
}
#ang {
width: 0;
height: 0;
border-top: 175px solid #333;
border-right: 500px solid transparent;
}
Javascript
$(window).scroll(function() {
var pos = $(window).scrollTop(), // Current scroll position
max = 300, // How quickly we want the animation to finish (in pixels)
box = 50, // Collapsed height of the box
ang = 0; // Collapsed height of the angle
/* Only make changes if we are within the limit of our max variable
* If this condition is not met, the box and angle will be collapsed
* I found this necessary because scrollTop doesn't produce consistent
* values and quite often the box wouldn't fully collapse */
if (pos <= max) {
// Max height - (scroll percentage x (max height - min height))
box = 125 - (pos / max * 75);
ang = 175 - (pos / max * 175);
}
// Adjust the height of the box and the angle
$('#box').css({ 'height': box + 'px' });
$('#ang').css({ 'border-top-width': ang + 'px' });
});
See my JS Bin for a demo.
I'm desperately searching for solution for my client. I have graphic - something like that:
And I want to be able to take the line with circle in the center and drag it to right or left. And it will be hiding and unhiding my two full images. It's basically two images on the same place, just with another z-index I think.
I think it's possible to do it with JavaScript, but I don't know of any functions or methods for this option.
Here is my solution:
The HTML is pretty simple, just two divs for the images and one for the drag:
<div class="img" id="img1"></div>
<div class="img" id="img2"></div>
<div id="drag"></div>
For the CSS, the important part is to absolute position all the divs and give a background image.
As for the Javascript, with a little help from jQuery, we listen for the mouse events, make some calculations and adjust the CSS of the second image:
$('#drag').on('mousedown', function(e){
var $self = $(this),
dragPos = $self.position().left + $self.width()/2,
imgWidth = $('#img1').width();
$(document).on('mouseup', function(e){
$(document).off('mouseup').off('mousemove');
});
$(document).on('mousemove', function(me){
var mx = me.pageX - e.pageX + dragPos
$self.css({ left: mx });
$('#img2').css({
width: imgWidth - mx,
left: mx,
backgroundPosition: -mx + 'px 0px',
});
});
});
From there, I believe it's pretty easy to customize it and give it a unique look.
Hope this helps!
JsFiddle Demo
Something like this alphamask plugin may do the trick, though I'm not sure how simple it would be for you to implement in the manner of your slider example.
Actually quite simple. The first step is to make it work manually. I'd set it up as follows:
<div class="wrap" id="wrap1">
<div class="img-wrap img1"></div>
<div class="img-wrap img2"></div>
<div>
With CSS as follows:
.wrap {
position: relative;
width: 300px;
height: 300px;
}
.img-wrap {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
.img1 {
z-index: 1;
background: url(bg1.png) no-repeat 0px 0px;
}
.img2 {
z-index: 2;
background: url(bg1.png) no-repeat 0px 0px;
}
Now some JavaScript (with jQuery) to set a position (you can call this when you move a slider over the top later):
function setPosition(percentage){
// get the width of the container
var w = $('#wrap1').width();
// work out the width of left panel
var w1 = Math.floor(w * percentage);
// and the right panel
var w2 = w - w1;
// set the width of the right panel
// move it right by the width of the left panel
// and move the background back by the width of the left panel
$('#wrap1 .img2').css({
width: w2,
left: w1,
backgroundPosition: -w1 + 'px 0px',
});
}
You now just have to decide how to do the dragging. You could even just do it on mouseOver. Easy!