I have created a simple cube in CSS and would like to be able to rotate it around with click and drag to display text on the sides etc, but every time you click and drag, it resets to the original position. How could I store the last rotated angle to be able to ensure it starts where it left off? I appreciate any help. Here is the code:
// Select the Cube
const cube = document.querySelector(".cube");
const body = document.querySelector("body");
// Get the x, y position when click
window.addEventListener("mousedown", function(e) {
const x = e.clientX;
const y = e.clientY;
// rotate
window.addEventListener("mousemove", moveRotate);
function moveRotate(e) {
cube.style.transform = `
rotateX(${-(e.clientY - y) / 2}deg)
rotateY(${(e.clientX - x) / 2}deg)`;
body.style.cursor = "grabbing";
}
window.addEventListener("mouseup", function() {
window.removeEventListener("mousemove", moveRotate);
body.style.cursor = "context-menu";
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: rgb(0, 0, 0);
}
.cube {
position: absolute;
width: 300px;
height: 300px;
transform-style: preserve-3d;
}
.cube div {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform-style: preserve-3d;
}
.cube div span {
color: azure;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(black, rgb(0, 255, 0));
transform: rotateY(calc(90deg * var(--i))) translateZ(150px);
}
.top {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
background: #222;
transform: rotateX(90deg) translateZ(150px);
}
.top div {
color: white;
position: absolute;
top: 45%;
left: 35%
}
.bottom {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
background: rgba(0, 255, 0);
transform: rotateX(90deg) translateZ(-150px);
}
<body>
<div class="cube">
<div class="top"></div>
<div class="bottom"></div>
<div class="sides">
<span class=front style="--i:0;">0</span>
<span class=left style="--i:1;">1</span>
<span class=back style="--i:2;">2</span>
<span class=right style="--i:3;">3</span>
</div>
</div>
</body>
You need to store the last calculated rotation value on the mouseUp event. Then add it to the value of the new calculated rotation in the mouseMove listener. The initial value must be set to zero outside both events.
// Select the Cube
const cube = document.querySelector(".cube");
const body = document.querySelector("body");
let last_x = 0,
last_y = 0
// Get the x, y position when click
window.addEventListener("mousedown", function (e)
{
const x = e.clientX;
const y = e.clientY;
let new_x = 0,
new_y = 0;
// rotate
window.addEventListener("mousemove", moveRotate);
function moveRotate(e)
{
new_x = ((e.clientX - x) / 2) + last_x
new_y = (-(e.clientY - y) / 2) + last_y
cube.style.transform =`
rotateX(${new_y}deg)
rotateY(${new_x}deg)`;
body.style.cursor = "grabbing";
}
window.addEventListener("mouseup",function ()
{
last_x = new_x
last_y = new_y
window.removeEventListener("mousemove", moveRotate);
body.style.cursor = "context-menu";
});
});
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body
{
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: rgb(0, 0, 0);
}
.cube
{
position: absolute;
width: 300px;
height: 300px;
transform-style: preserve-3d;
}
.cube div
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform-style: preserve-3d;
}
.cube div span
{
color:azure;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(black, rgb(0, 255, 0));
transform: rotateY(calc(90deg * var(--i))) translateZ(150px);
}
.top
{
position: absolute;
top:0;
left: 0;
width: 300px;
height: 300px;
background: #222;
transform: rotateX(90deg) translateZ(150px);
}
.top div
{
color: white;
position: absolute;
top: 45%;
left: 35%
}
.bottom
{
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
background:rgba(0, 255,0);
transform: rotateX(90deg) translateZ(-150px);
}
<div class="cube">
<div class="top"></div>
<div class="bottom"></div>
<div class="sides">
<span class=front style="--i:0;">0</span>
<span class=left style="--i:1;">1</span>
<span class=back style="--i:2;">2</span>
<span class=right style="--i:3;">3</span>
</div>
</div>
Related
How to make the picture not spin, but be in the same position when tracking the mouse movement. Or maybe I need to write the code in a different way? I've already tried many options, but since I'm just learning JS, I don't know in which direction to move. An example where the picture is not spinning link . I will be grateful for your help.
Here is my code:
document.querySelector("body").addEventListener("mousemove", eyeball);
function eyeball() {
const eye = document.querySelectorAll(".eye");
eye.forEach(function(eye) {
let x = (eye.getBoundingClientRect().left) + (eye.clientWidth / 2);
let y = (eye.getBoundingClientRect().top) + (eye.clientHeight / 2);
let radian = Math.atan2(event.pageX - x, event.pageY - y);
let rotation = (radian * (180 / Math.PI) * -1) + 270;
eye.style.transform = "rotate(" + rotation + "deg)"
});
}
.contact {
display: flex;
margin: 0 auto;
justify-content: center;
align-items: center;
z-index: 1;
}
.box {
display: flex;
margin: 0;
top: 35px;
right: 0;
bottom: 0;
left: 0;
position: absolute;
align-items: center;
justify-content: center;
}
.box .eye {
position: relative;
width: 200px;
height: 200px;
display: block;
background-color: pink;
border-radius: 50%;
z-index: -1;
}
.box .eye::before {
content: "";
position: fixed;
top: 50%;
left: 35px;
transform: translate(-50%, -50%);
width: 70px;
height: 70px;
border-radius: 50%;
background-image: url(https://cdn-icons-png.flaticon.com/512/179/179531.png);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
box-sizing: border-box;
}
<section class="contact">
<div class="box">
<div class="eye"></div>
</div>
</section>
On the web site you included the eye isn't really tracing a circle shape, it's bounded by a rectangle representing scaled screen dimensions.
document.querySelector("body").addEventListener("mousemove", eyeball);
function eyeball() {
const pupils = document.querySelectorAll(".pupil");
pupils.forEach((pupil) => {
const mx = event.pageX
const my = event.pageY
// scale mouse position from screen space to percentages 15% - 85%
const vx = scale(mx, 0, innerWidth, 15, 85)
const vy = scale(my, 0, innerHeight, 15, 85)
pupil.style.transform = `translate(${vx}%, ${vy}%)`
});
}
// scales value from inMin - inMax range to outMin - outMax range
function scale(value, inMin, inMax, outMin, outMax) {
const percent = (value - inMin) / (inMax - inMin);
const out = percent * (outMax - outMin) + outMin;
return out
}
.contact {
display: flex;
margin: 0 auto;
justify-content: center;
align-items: center;
z-index: 1;
}
.box {
display: flex;
margin: 0;
top: 35px;
right: 0;
bottom: 0;
left: 0;
position: absolute;
align-items: center;
justify-content: center;
}
.box .eye {
position: relative;
width: 200px;
height: 200px;
display: block;
background-color: pink;
border-radius: 50%;
z-index: -1;
}
.box .eye .pupil {
width: 100px;
height: 100px;
background-image: url(https://cdn-icons-png.flaticon.com/512/179/179531.png);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
box-sizing: border-box;
}
<section class="contact">
<div class="box">
<div class="eye">
<div class="pupil"></div>
</div>
</div>
</section>
I am trying to create a linear animation with pipes just like the flappy bird game. When I have one single pipe, I see a random gap and it works well, but when I clone all the pipes, there is no longer a gap at a random position.
How can I give the gaps in the pipe a random position when I have multiple pipes, and why is it not working as expected?
var block = document.getElementById("block");
//clone the pipe multiples times
var blockClone;
for (var i = 0; i < 4; i++) {
blockClone = block.cloneNode(true);
// the true is for deep cloning
//append all clones to original pipe
block.appendChild(blockClone);
//remove animtion from clones
blockClone.style.animationName = "none";
}
//gap inbetween each pipe
var hole = document.getElementById("hole");
var holeClone;
for (var i = 0; i < 4; i++) {
holeClone = hole.cloneNode(true);
// the true is for deep cloning
//append all clones to original pipe
blockClone.appendChild(hole);
block.appendChild(hole);
//remove animtion from clones
holeClone.style.animationName = "none";
hole.addEventListener('animationiteration', () => {
var random = -((Math.random() * 300) + 150);
hole.style.top = random + "px";
});
}
body {
text-align: center;
position: fixed;
width: 100%;
height: 100%;
}
* {
padding: 0;
margin: 0;
}
#game {
width: 100%;
height: 500px;
border: 1px solid red;
margin: auto;
overflow: hidden;
}
/* pipe version 1 */
#block {
width: 60px;
height: 500px;
background-color: green;
background-image: url("https://l.dropbox.com/s/4jz7uq4e25o8su5/sketch-1664244879.png?dl=0");
background-size: cover;
position: absolute;
left: 100px;
animation: block 5s infinite linear;
}
#hole {
width: 60px;
height: 210px;
background-color: red;
position: absolute;
left: 0px;
top: -10px;
/* animation: block 5s infinite
linear;*/
background-image: url("https://dldropbox.com/s/j7enawgtuepj7au/sketch-166428805830.png?dl=0");
background-size: cover;
}
#character {
width: 40px;
height: 40px;
background-color: none;
position: absolute;
top: 100px;
left: 40px;
border-radius: ;
z-index: 1;
background-color: red;
}
}
#overlay {
position: fixed;
display: none;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: black;
cursor: none;
opacity: 0.3;
text-align: center;
}
/* used to prevent user from tapping even after the game has ended*/
.mainoverlay {
position: fixed;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: none;
opacity: 0;
}
#blokhold {
animation: block 5s infinite linear;
}
#keyframes block {
0% {
left: 350px
}
100% {
left: -890px
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="game">
<div id="blokhold">
<div id="block">
<div id="hole"></div>
</div>
</div>
<div id="character"></div>
</div>
I have some problem about JavaScript and using if in it. I have some experiences in PHP, but this is another world for me. I need to do something like this: I have "progress bar" with two buttons (+ and -), when I press button the value in function will change +- 0.1 which move the bar and change %.
I want to change to color of the progress bar when it's more then 100%. I tried to make another fill called filler with 0 rotate. When x is 1 or more then rotate depends on value2 = y + 0.1 per click. It works, but with 2 + buttons and I want it to only with one. If(x>1) doesn't work with document.write.
images:
demo:
https://jsfiddle.net/dmytxja2
var x = 0;
var y = 0;
const gaugeElement = document.querySelector(".gauge");
function setGaugeValue(gauge, value) {
if (value < 0 || value > 3) {
return;
}
gauge.querySelector(".gauge__fill").style.transform = `rotate(${value / 2}turn)`;
gauge.querySelector(".gauge__filler").style.transform = `rotate(${0}turn)`;
value2 = y;
gauge.querySelector(".gauge__filler").style.transform = `rotate(${value2 / 2}turn)`;
gauge.querySelector(".gauge__cover").textContent = `${Math.round(value * 100)}%`;
}
setGaugeValue(gaugeElement, x);
if (x >= 1) {
var cc = document.getElementById('outer');
cc.style.visibility = "visible";
}
document.write('<button id="iner" onclick="setGaugeValue(gaugeElement, x = x + 0.1)">+</button>');
document.write('<button id="outer" hidden="hidden" onclick="setGaugeValue(gaugeElement, y = y + 0.1)">+</button>');
document.write('<button onclick="setGaugeValue(gaugeElement, x = x - 0.1)">-</button>');
document.write('<button onclick="alert(x);">test</button>');
.gauge {
width: 100%;
max-width: 250px;
font-family: "Roboto", sans-serif;
font-size: 32px;
color: #004033;
}
.gauge__body {
width: 100%;
height: 0;
padding-bottom: 50%;
background: #b4c0be;
position: relative;
border-top-left-radius: 100% 200%;
border-top-right-radius: 100% 200%;
overflow: hidden;
}
.gauge__fill {
position: absolute;
top: 100%;
left: 0;
width: inherit;
height: 100%;
background: red;
transform-origin: center top;
transform: rotate(0.25turn);
transition: transform 0.2s ease-out;
}
.gauge__filler {
position: absolute;
top: 100%;
left: 0;
width: inherit;
height: 100%;
background: green;
transform-origin: center top;
transform: rotate(0.25turn);
transition: transform 0.2s ease-out;
}
.gauge__cover {
width: 75%;
height: 150%;
background: #ffffff;
border-radius: 50%;
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
/* Text */
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 25%;
box-sizing: border-box;
}
<div class="gauge">
<div class="gauge__body">
<div class="gauge__fill"></div>
<div class="gauge__filler"></div>
<div class="gauge__cover"></div>
</div>
</div>
You must enter the condition inside the function to be checked each time the function is called
In your code, the condition is only checked for the first time, and because the result is false, it does not change
You have also assigned the hidden parameter to the button with the outer id
But when displaying outer you use style.visibility which has no effect
Your modified code:
var x = 0;
var y = 0;
const gaugeElement = document.querySelector(".gauge");
function setGaugeValue(gauge, value) {
if (value < 0 || value > 3) {
return;
}
gauge.querySelector(".gauge__fill").style.transform = `rotate(${value / 2}turn)`;
gauge.querySelector(".gauge__filler").style.transform = `rotate(${0}turn)`;
value2 = y;
gauge.querySelector(".gauge__filler").style.transform = `rotate(${value2 / 2}turn)`;
gauge.querySelector(".gauge__cover").textContent = `${Math.round(value * 100)}%`;
if (x >= 1) {
var cc = document.getElementById('outer');
cc.style.display = "inline";
}
}
setGaugeValue(gaugeElement, x);
document.write('<button id="iner" onclick="setGaugeValue(gaugeElement, x = x + 0.1)">+</button>');
document.write('<button id="outer" style="display:none;" onclick="setGaugeValue(gaugeElement, y = y + 0.1)">+</button>');
document.write('<button onclick="setGaugeValue(gaugeElement, x = x - 0.1)">-</button>');
document.write('<button onclick="alert(x);">test</button>');
.gauge {
width: 100%;
max-width: 250px;
font-family: "Roboto", sans-serif;
font-size: 32px;
color: #004033;
}
.gauge__body {
width: 100%;
height: 0;
padding-bottom: 50%;
background: #b4c0be;
position: relative;
border-top-left-radius: 100% 200%;
border-top-right-radius: 100% 200%;
overflow: hidden;
}
.gauge__fill {
position: absolute;
top: 100%;
left: 0;
width: inherit;
height: 100%;
background: red;
transform-origin: center top;
transform: rotate(0.25turn);
transition: transform 0.2s ease-out;
}
.gauge__filler {
position: absolute;
top: 100%;
left: 0;
width: inherit;
height: 100%;
background: green;
transform-origin: center top;
transform: rotate(0.25turn);
transition: transform 0.2s ease-out;
}
.gauge__cover {
width: 75%;
height: 150%;
background: #ffffff;
border-radius: 50%;
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
/* Text */
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 25%;
box-sizing: border-box;
}
<div class="gauge">
<div class="gauge__body">
<div class="gauge__fill"></div>
<div class="gauge__filler"></div>
<div class="gauge__cover"></div>
</div>
</div>
BUT:
This code is very, very bad
As far as I realized
You wanted to make something like this
My Code :
var x = 0;
var deg = 0;
const gaugeElement = document.querySelector(".gauge");
const gauge__fill = gaugeElement.querySelector(".gauge__fill");
const gauge__cover = document.querySelector(".gauge__cover");
function setGaugeValue(btn) {
if (x >= 0) {
if (gauge__fill.style.transform == "rotate(180deg)" && btn == 'plus') {
deg = 0;
}
if (gauge__fill.style.transform == "rotate(18deg)" && btn == 'minus' && x != 0) {
deg = 180;
} else {
if (btn == 'plus') {
deg += 18;
} else {
deg -= 18;
}
}
gauge__fill.style.transform = 'rotate(' + deg + 'deg)';
gauge__cover.textContent = `${x * 10}%`;
if (x >= 11) {
gauge__fill.style.background = "green";
} else {
gauge__fill.style.background = "red";
}
}
}
document.getElementById("plus").addEventListener("click", function() {
x += 1;
setGaugeValue('plus');
});
document.getElementById("minus").addEventListener("click", function() {
if (x > 0) {
x -= 1;
setGaugeValue('minus');
}
});
document.getElementById("test").addEventListener("click", function() {
alert(x);
});
.gauge {
width: 100%;
max-width: 250px;
font-family: "Roboto", sans-serif;
font-size: 32px;
color: #004033;
}
.gauge__body {
width: 100%;
height: 0;
padding-bottom: 50%;
background: #b4c0be;
position: relative;
border-top-left-radius: 100% 200%;
border-top-right-radius: 100% 200%;
overflow: hidden;
}
.gauge__fill {
position: absolute;
top: 100%;
left: 0;
width: inherit;
height: 100%;
background: red;
transform-origin: center top;
transition: transform 0.2s ease-out;
}
.gauge__cover {
width: 75%;
height: 150%;
background: #ffffff;
border-radius: 50%;
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
/* Text */
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 25%;
box-sizing: border-box;
}
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="real.css">
<title>Nutriadapt</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="gauge">
<div class="gauge__body">
<div class="gauge__fill"></div>
<div class="gauge__cover">0%</div>
</div>
</div>
<button id="plus">+</button>
<button id="minus">-</button>
<button id="test">test</button>
</body>
</html>
How to detect top right bottom left screen area JavaScript? I have four arrow for slider but I wanna display only when mouse hover on particular area.
$('.container').mousemove(function (e) {
if (e.clientY < $('.container').height() / 2) {
console.log('top');
} else {
console.log('bottom');
}
if (e.client X < $('.container').width() / 2) {
console.log('left');
} else {
console.log('right');
}
});
Would you consider a CSS :hover suggestion? It may be simpler. Added font awesome arrows as example.
html,
body {
height: 100%;
width: 100%;
}
.top {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 40px;
background: lightgray;
}
.left {
position: absolute;
top: 40px;
left: 0;
bottom: 40px;
width: 40px;
background: lightgray;
}
.right {
position: absolute;
top: 40px;
right: 0;
bottom: 40px;
width: 40px;
background: lightgray;
}
.bottom {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 40px;
background: lightgray;
}
.top:hover,
.left:hover,
.right:hover,
.bottom:hover {
cursor: pointer;
background: gray;
}
.top:hover i,
.left:hover i,
.right:hover i,
.bottom:hover i {
display: block;
}
i.fa {
display: none;
text-align: center;
line-height: 40px;
font-size: 24px;
}
i.fa.fa-arrow-right,
i.fa.fa-arrow-left {
position: absolute;
top: 50%;
transform: translate(50%, -50%);
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="top"><i class="fa fa-arrow-up"></i></div>
<div class="left"><i class="fa fa-arrow-left"></i></div>
<div class="right"><i class="fa fa-arrow-right"></i></div>
<div class="bottom"><i class="fa fa-arrow-down"></i></div>
// define the rectangular areas
var areas = {
top: [0, 0, 500, 100], // [startX, startY, endX, endY]
left: [0, 0, 100, 500],
right: [100, 0, 500, 500],
bottom: [0, 400, 500, 500]
};
function getArea(x, y) {
for (var key in areas) {
var area = areas[key];
if (x <= area[0] && x >= area[2] && y <= area[1] && y >= area[3]) return key;
}
return null;
}
$('.container').mousemove(function (e) {
console.clear && console.clear();
console.log(getArea(e.clientX, e.clientY));
});
I have a modal containing one or more images and these images can rotate.
My issue is when image rotate it overflow the parent div. I wish to have the container to change dimension to always fit the image (images).
I created a codepen to have a look.
I tried to change many and many css properties without success...
Jade:
.overlay
.fake-modal
.content
img.img(src='http://lorempixel.com/output/abstract-q-c-300-200-2.jpg')
.wrapper
button.left rotate left
button.right rotate right
Less:
.overlay {
background-color: rgba(0, 0, 0, .7);
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
.fake-modal {
background-color: #fff;
padding: 10px;
position: fixed;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
width: auto;
height: auto;
z-index: 1;
.content {
position: relative;
.wrapper {
position: absolute;
top: 10px;
right: 10px;
}
}
}
js:
var angle = 0;
var btnLeft = $('.left');
var btnRight = $('.right');
btnLeft.on('click', function (e) {
e.preventDefault();
angle = angle - 90;
rotate(angle);
});
btnRight.on('click', function (e) {
e.preventDefault();
angle = angle + 90;
rotate(angle);
});
function rotate(rotateDegrees) {
var r = 'rotate(' + rotateDegrees + 'deg)';
var img = $('.img');
img.css({
'-moz-transform': r,
'-webkit-transform': r,
'-o-transform': r,
'-ms-transform': r
});
}
Solved using getBoundingClientRect()
Codepen: http://codepen.io/anon/pen/BNENge
you may set fixed width and height to div contaning image.
http://codepen.io/anon/pen/XbQXJP
`.overlay {
background-color: rgba(0, 0, 0, .7);
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
.fake-modal {
background-color: #fff;
padding: 10px;
position: fixed;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
width: auto;
height: auto;
z-index: 1;
.content {
position: relative;
.imgContainer {
position: relative;
width: 300px;
height: 200px;
.img {
position: absolute;
margin-left: -150px;
margin-top: -100px;
top: 50%;
left: 50%;
}
}
.wrapper {
position: absolute;
top: 10px;
right: 10px;
}
}
}`