CSS & JS not loading properly [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I got these scripts but they're not loading properly. Can't say for sure what the issue is but the CSS and JS don't look like they're being picked up. Cause the index.html isn't being rendered as it should.
I'm not sure what I'm doing wrong or what I'm missing. It's probably something annoyingly small.
I feel like I've referenced the css and js with the script and link tags, but it still doesn't get rendered.
I listed the three scripts below. Any ideas please?
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="style.css">
<div class='moon'>
<div class='crater1'></div>
<div class='crater2'></div>
<div class='crater3'></div>
</div>
<canvas id="canvas"></canvas>
<div id="sea"></div>
<div id="beach"></div>
<img src="https://dl.dropbox.com/s/2k0mtrxc2dqurmh/jumping.png" alt="jumping-people" id="people" />
<!--<img src="https://dl.dropbox.com/s/zoftkmdxyyqr8ce/belair.png" alt="jumping-people" id="car" />-->
<div id="merrywrap" class="merrywrap">
<div class="giftbox">
<div class="cover">
<div></div>
</div>
<div class="box"></div>
</div>
<div class="icons">
<div class="row">
<span>H</span>
<span>a</span>
<span>p</span>
<span>p</span>
<span>y</span>
</div>
<div class="row">
<span>B</span>
<span>i</span>
<span>r</span>
<span>r</span>
<span>t</span>
<span>h</span>
<span>d</span>
<span>a</span>
<span>y</span>
</div>
<div class="row">
<span>D</span>
<span>a</span>
<span>v</span>
<span>e</span>
<!-- <span>t</span>
<span>h</span>
<span>e</span>
<span>a</span>
<span>r</span>
<span>t</span> -->
</div>
</div>
</div>
<script src="style.js"></script>
<div id="video">
<!--<iframe width="255" height="155" src="https://www.youtube.com/embed/MrXBATtOtFY?controls=0&loop=1" frameborder="0" allowfullscreen></iframe>-->
</div>
style.css
/* Kaushan+Script, oregano, sail */
#import url('https://fonts.googleapis.com/css?family=Kaushan+Script');
html, body, .container {
height: 100%;
font-family: 'Kaushan Script','Sail', cursive;
}
body {
background: #e74;
overflow: hidden;
background-image: linear-gradient( to bottom, #190e14 ,#0d0d4b 30%, #c76075 80%, #e9b64b 95% );
background-image:
radial-gradient(circle at center bottom, #e9b64b ,#c76075 15%, #0d0d4b 75%, #190e14 90%);
}
div#beach,
canvas#canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
div#beach {
background-image: url(https://dl.dropbox.com/s/oe0oce2udq44bj5/beachsil2.png);
/* background-size: cover; */
background-position: bottom right;
background-size: 1700px;
background-repeat: no-repeat;
}
div#video {
position: absolute;
right: 243px;
bottom: 200px;
}
div#video iframe {
width: 255px;
height: 155px;
}
#people {
position: absolute;
bottom: 65px;
left: 40px;
width: 140px;
}
#car {
position: absolute;
bottom: 46px;
left: 180px;
width: 230px;
}
div#sea {
background-color: blue;
height: 85px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background-image:
radial-gradient(circle at center top, #23485a, #0d0246);
}
.merrywrap{
position: absolute;
right: 0px;
left: 0px;
bottom: 0px;
top: 0px;
background-color: #d44;
transition: background-color .5s ease;
}
.giftbox{
position: absolute;
width:300px;
height:200px;
left:50%;
margin-left: -150px;
bottom: 40px;
z-index:10;
&>div{
background: #34495e;
position: absolute;
&:after,&:before{
position: absolute;
content:"";
top: 0;
}
}
&:after{
position: absolute;
color:#fff;
width:100%;
content:"Click Me!";
left: 0;
bottom: 0;
font-size: 24px;
text-align: center;
transform:rotate(-20deg);
transform-origin:0 0;
}
.cover{
width:100%;
top: 0;
left: 0;
height:25%;
z-index:2;
&:before{
position: absolute;
height:100%;
left: 50%;
width:50px; transform:translateX(-50%);
background:#fdc56d;
}
&>div{
position: absolute;
width:50px;
height:50px;
left:50%;
top:-50px; transform:translateX(-50%);
&:before,&:after{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
content:"";
box-shadow:inset 0 0 0 15px #fdc56d;
border-radius:30px;
transform-origin:50% 100%;
}
&:before{
transform:translateX(-45%) skewY(40deg);
}
&:after{ transform:translateX(45%) skewY(-40deg);
}
}
}
.box{
right:5%;
left:5%;
height:80%;
bottom: 0;
&:before{
width:50px;
height:100%;
left:50%;
transform:translateX(-50%);
background:#fdc56d;
}
&:after{
width:100%;
height:30px;
background:rgba(0,0,0,0.2);
}
}
}
.icons{
position:absolute;
left: 10px;
/*top:50%;
width: 100%;*/
height: auto;
transform:translateY(10px) rotate(-20deg);
.row{
width:100%;
text-align: center;
span{
color: #e5e5e5;
text-shadow: 4px 4px 0 rgba(96, 125, 139, 0.4);
font-size: 50px;
display: inline-block;
opacity:0;
transition: transform 0.5s ease-in, opacity 0.7s;
}
}
}
.step-1{
.giftbox{
animation:wobble 0.5s linear infinite forwards;
}
.cover{
animation:wobble 0.5s linear infinite 0.1s forwards;
}
.icons .row span{
opacity:1;
}
}
.step-2 .giftbox:after{
opacity:0;
}
.step-3 .giftbox,
.step-4 .giftbox{
opacity: 0;
z-index:1;
&:after{
opacity:0;
}
}
.step-2{
.giftbox{
.cover{
animation:flyUp 0.4s ease-in forwards;
}
.box{
animation:flyDown 0.2s ease-in 0.05s forwards;
}
}
}
#keyframes wobble{
25%{
transform:rotate(4deg);
}
75%{
transform:rotate(-2deg);
}
}
#keyframes flyUp{
75%{
opacity:1;
}
100%{
transform:translateY(-1000px) rotate(20deg);
opacity:0;
}
}
#keyframes flyDown{
75%{
opacity:1;
}
100%{
transform:translateY(100%);
opacity:0;
}
}
.step-1 .icons .row span{
opacity:0;
}
.step-1 .icons .row span:first-child {
transform: translateY(700%) translateX(600%);
}
.step-1 .icons .row span:nth-child(2) {
transform: translateY(700%) translateX(500%);
}
.step-1 .icons .row span:nth-child(3) {
transform: translateY(700%) translateX(400%);
}
.step-1 .icons .row span:nth-child(4) {
transform: translateY(700%) translateX(300%);
}
.step-1 .icons .row span:nth-child(5) {
transform: translateY(700%) translateX(200%);
}
.step-1 .icons .row span:nth-child(6) {
transform: translateY(700%) translateX(100%);
}
.step-1 .icons .row span:nth-child(7) {
transform: translateY(700%) translateX(0);
}
.step-1 .icons .row span:nth-child(8) {
transform: translateY(700%) translateX(-100%);
}
.step-1 .icons .row span:nth-child(9) {
transform: translateY(700%) translateX(-200%);
}
.step-1 .icons .row span:nth-child(10) {
transform: translateY(700%) translateX(-300%);
}
.step-1 .icons .row span:nth-child(11) {
transform: translateY(700%) translateX(-400%);
}
.step-1 .icons .row span:nth-child(12) {
transform: translateY(700%) translateX(-500%);
}
.step-1 .icons .row span:nth-child(13) {
transform: translateY(700%) translateX(-600%);
}
.step-2 .icons .row span:nth-child(2) {
-webkit-transition-delay: 0.1s;
transition-delay: 0.1s;
}
.step-2 .icons .row span:nth-child(3) {
-webkit-transition-delay: 0.15s;
transition-delay: 0.15s;
}
.step-2 .icons .row span:nth-child(4) {
-webkit-transition-delay: 0.2s;
transition-delay: 0.2s;
}
.step-2 .icons .row span:nth-child(5) {
-webkit-transition-delay: 0.25s;
transition-delay: 0.25s;
}
.step-2 .icons .row span:nth-child(6) {
-webkit-transition-delay: 0.3s;
transition-delay: 0.3s;
}
.step-2 .icons .row span:nth-child(7) {
-webkit-transition-delay: 0.35s;
transition-delay: 0.35s;
}
.step-2 .icons .row span:nth-child(8) {
-webkit-transition-delay: 0.4s;
transition-delay: 0.4s;
}
.step-2 .icons .row span:nth-child(9) {
-webkit-transition-delay: 0.45s;
transition-delay: 0.45s;
}
.step-2 .icons .row span:nth-child(10) {
-webkit-transition-delay: 0.5s;
transition-delay: 0.5s;
}
.step-2 .icons .row span:nth-child(11) {
-webkit-transition-delay: 0.55s;
transition-delay: 0.55s;
}
.step-2 .icons .row span:nth-child(12) {
-webkit-transition-delay: 0.6s;
transition-delay: 0.6s;
}
.step-2 .icons .row span:nth-child(13) {
-webkit-transition-delay: 0.65s;
transition-delay: 0.65s;
}
.step-2 .icons span,.step-3 .icons span,.step-4 .icons span {
opacity: 1;
transition-timing-function: cubic-bezier(0.000, 0.000, 0.200, 0.910);
}
.step-4 .icons .row span,.step-3 .icons .row span {
/*animation: wobble 0.6s linear infinite forwards;*/
color: #c6e2ff;
animation: neon .08s ease-in-out infinite alternate;
}
.step-4 .icons .row span:nth-child(even),.step-3 .icons .row span:nth-child(even) {
animation-duration: 0.7s;
}
#keyframes neon {
from {
text-shadow:
0 0 6px rgba(202,228,225,0.92),
0 0 30px rgba(202,228,225,0.34),
0 0 12px rgba(30,132,242,0.52),
0 0 21px rgba(30,132,242,0.92),
0 0 34px rgba(30,132,242,0.78),
0 0 54px rgba(30,132,242,0.92);
}
to {
text-shadow:
0 0 6px rgba(202,228,225,0.98),
0 0 30px rgba(202,228,225,0.42),
0 0 12px rgba(30,132,242,0.58),
0 0 22px rgba(30,132,242,0.84),
0 0 38px rgba(30,132,242,0.88),
0 0 60px rgba(30,132,242,1);
}
}
.moon {
position: absolute;
top: 10%;
right: 200px;
width: 100px;
height: 100px;
border-radius: 50%;
background: #ddd;
box-shadow: inset 20px -10px 0 0 #b9b9b9;
}
.moon .crater1 {
position: absolute;
width: 30px;
height: 30px;
border-radius: 50%;
background: #bbb;
box-shadow: inset -3px 1.5px 0 0 #aaa;
top: 20px;
right: 20px;
}
.moon .crater2 {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background: #bbb;
box-shadow: inset -1px 0.5px 0 0 #aaa;
top: 45px;
right: 50px;
}
.moon .crater3 {
position: absolute;
width: 15px;
height: 15px;
border-radius: 50%;
background: #bbb;
box-shadow: inset -1.5px 0.75px 0 0 #aaa;
top: 60px;
right: 25px;
}
#media (min-width: 1000px) {
.icons { left: 30px; }
.icons .row span { font-size: 56px; }
#people {
left: 80px;
bottom: 70px;
width: 160px;
}
div#beach {
background-size: 2000px;
}
div#video {
right: 290px;
bottom: 235px;
}
div#video iframe {
width: 295px;
height: 185px;
}
.moon {
right: 230px;
}
}
script.js
window.requestAnimFrame = ( function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ) {
window.setTimeout( callback, 1000 / 60 );
};
})();
var canvas = document.getElementById( 'canvas' ),
ctx = canvas.getContext( '2d' ),
// full screen dimensions
cw = window.innerWidth,
ch = window.innerHeight,
// firework collection
fireworks = [],
// particle collection
particles = [],
hue = 120,
limiterTotal = 5,
limiterTick = 0,
timerTotal = 80,
timerTick = 0,
mousedown = false,
mx,
my;
canvas.width = cw;
canvas.height = ch;
function random( min, max ) {
return Math.random() * ( max - min ) + min;
}
// calculate the distance between two points
function calculateDistance( p1x, p1y, p2x, p2y ) {
var xDistance = p1x - p2x,
yDistance = p1y - p2y;
return Math.sqrt( Math.pow( xDistance, 2 ) + Math.pow( yDistance, 2 ) );
}
// create firework
function Firework( sx, sy, tx, ty ) {
// actual coordinates
this.x = sx;
this.y = sy;
// starting coordinates
this.sx = sx;
this.sy = sy;
// target coordinates
this.tx = tx;
this.ty = ty;
// distance from starting point to target
this.distanceToTarget = calculateDistance( sx, sy, tx, ty );
this.distanceTraveled = 0;
this.coordinates = [];
this.coordinateCount = 3;
// populate initial coordinate collection with the current coordinates
while( this.coordinateCount-- ) {
this.coordinates.push( [ this.x, this.y ] );
}
this.angle = Math.atan2( ty - sy, tx - sx );
this.speed = 2;
this.acceleration = 1.05;
this.brightness = random( 50, 70 );
// circle target indicator radius
this.targetRadius = 1;
}
// update firework
Firework.prototype.update = function( index ) {
// remove last item in coordinates array
this.coordinates.pop();
// add current coordinates to the start of the array
this.coordinates.unshift( [ this.x, this.y ] );
// cycle the circle target indicator radius
if( this.targetRadius < 8 ) {
this.targetRadius += 0.3;
} else {
this.targetRadius = 1;
}
// speed up the firework
this.speed *= this.acceleration;
// get the current velocities based on angle and speed
var vx = Math.cos( this.angle ) * this.speed,
vy = Math.sin( this.angle ) * this.speed;
// how far will the firework have traveled with velocities applied?
this.distanceTraveled = calculateDistance( this.sx, this.sy, this.x + vx, this.y + vy );
// if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached
if( this.distanceTraveled >= this.distanceToTarget ) {
createParticles( this.tx, this.ty );
// remove the firework, use the index passed into the update function to determine which to remove
fireworks.splice( index, 1 );
} else {
// target not reached, keep traveling
this.x += vx;
this.y += vy;
}
}
// draw firework
Firework.prototype.draw = function() {
ctx.beginPath();
// move to the last tracked coordinate in the set, then draw a line to the current x and y
ctx.moveTo( this.coordinates[ this.coordinates.length - 1][ 0 ], this.coordinates[ this.coordinates.length - 1][ 1 ] );
ctx.lineTo( this.x, this.y );
ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)';
ctx.stroke();
ctx.beginPath();
// draw the target for this firework with a pulsing circle
ctx.arc( this.tx, this.ty, this.targetRadius, 0, Math.PI * 2 );
ctx.stroke();
}
// create particle
function Particle( x, y ) {
this.x = x;
this.y = y;
// track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails
this.coordinates = [];
this.coordinateCount = 5;
while( this.coordinateCount-- ) {
this.coordinates.push( [ this.x, this.y ] );
}
// set a random angle in all possible directions, in radians
this.angle = random( 0, Math.PI * 2 );
this.speed = random( 1, 10 );
// friction will slow the particle down
this.friction = 0.95;
// gravity will be applied and pull the particle down
this.gravity = 1;
// set the hue to a random number +-20 of the overall hue variable
this.hue = random( hue - 20, hue + 20 );
this.brightness = random( 50, 80 );
this.alpha = 1;
// set how fast the particle fades out
this.decay = random( 0.015, 0.03 );
}
// update particle
Particle.prototype.update = function( index ) {
// remove last item in coordinates array
this.coordinates.pop();
// add current coordinates to the start of the array
this.coordinates.unshift( [ this.x, this.y ] );
// slow down the particle
this.speed *= this.friction;
// apply velocity
this.x += Math.cos( this.angle ) * this.speed;
this.y += Math.sin( this.angle ) * this.speed + this.gravity;
// fade out the particle
this.alpha -= this.decay;
// remove the particle once the alpha is low enough, based on the passed in index
if( this.alpha <= this.decay ) {
particles.splice( index, 1 );
}
}
// draw particle
Particle.prototype.draw = function() {
ctx. beginPath();
// move to the last tracked coordinates in the set, then draw a line to the current x and y
ctx.moveTo( this.coordinates[ this.coordinates.length - 1 ][ 0 ], this.coordinates[ this.coordinates.length - 1 ][ 1 ] );
ctx.lineTo( this.x, this.y );
ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
ctx.stroke();
}
// create particle group/explosion
function createParticles( x, y ) {
// increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though
var particleCount = 30;
while( particleCount-- ) {
particles.push( new Particle( x, y ) );
}
}
// main demo loop
function loop() {
// this function will run endlessly with requestAnimationFrame
requestAnimFrame( loop );
// increase the hue to get different colored fireworks over time
hue += 0.5;
// normally, clearRect() would be used to clear the canvas
// we want to create a trailing effect though
// setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
ctx.globalCompositeOperation = 'destination-out';
// decrease the alpha property to create more prominent trails
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect( 0, 0, cw, ch );
// change the composite operation back to our main mode
// lighter creates bright highlight points as the fireworks and particles overlap each other
ctx.globalCompositeOperation = 'lighter';
// loop over each firework, draw it, update it
var i = fireworks.length;
while( i-- ) {
fireworks[ i ].draw();
fireworks[ i ].update( i );
}
// loop over each particle, draw it, update it
var i = particles.length;
while( i-- ) {
particles[ i ].draw();
particles[ i ].update( i );
}
// launch fireworks automatically to random coordinates, when the mouse isn't down
if( timerTick >= timerTotal ) {
if( !mousedown ) {
// start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of the top half of the screen
fireworks.push( new Firework( cw / 2, ch, random( 0, cw ), random( 0, ch / 2 ) ) );
timerTick = 0;
}
} else {
timerTick++;
}
// limit the rate at which fireworks get launched when mouse is down
if( limiterTick >= limiterTotal ) {
if( mousedown ) {
// start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target
fireworks.push( new Firework( cw / 2, ch, mx, my ) );
limiterTick = 0;
}
} else {
limiterTick++;
}
}
window.onload=function(){
var merrywrap=document.getElementById("merrywrap");
var box=merrywrap.getElementsByClassName("giftbox")[0];
var step=1;
var stepMinutes=[2000,2000,1000,1000];
function init(){
box.addEventListener("click",openBox,false);
}
function stepClass(step){
merrywrap.className='merrywrap';
merrywrap.className='merrywrap step-'+step;
}
function openBox(){
if(step===1){
box.removeEventListener("click",openBox,false);
}
stepClass(step);
if(step===3){
}
if(step===4){
reveal();
return;
}
setTimeout(openBox,stepMinutes[step-1]);
step++;
}
init();
}
function reveal() {
document.querySelector('.merrywrap').style.backgroundColor = 'transparent';
loop();
var w, h;
if(window.innerWidth >= 1000) {
w = 295; h = 185;
}
else {
w = 255; h = 155;
}
var ifrm = document.createElement("iframe");
ifrm.setAttribute("src", "https://www.youtube.com/embed/MrXBATtOtFY?controls=0&loop=1&autoplay=1");
//ifrm.style.width = `${w}px`;
//ifrm.style.height = `${h}px`;
ifrm.style.border = 'none';
document.querySelector('#video').appendChild(ifrm);
}

You are referencing
<script src="style.js"></script>
I assume you ment to reference the "script.js" file..
<script src="script.js"></script>
I also suggest to add the async keyword to the tag for better performence:
https://flaviocopes.com/javascript-async-defer/

Related

If text is longer than its container lower the font size till the text can fit in

We have a container that contains an animating text.
We define a default font size for the text, but we want to lower the font size if the text exceeds the container's width so that the text no matter how long it is can fit into the container in one line.
Here is my code so far:
//The Text That would be fit into the container
let mytext = 'I was sent to earth to protect you!';
//The function to determine mytext width
function getTextWidth(text, font) {
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
};
//width of the upperGuide container
let width = document.getElementsByClassName("upperGuideContainer")[0].clientWidth;
let text_Length;
let default_size = 5.6;
/* Keep lowering the default font size till the text_Length is smaller than
its container width So that the text can fit in the container */
do {
text_Length = getTextWidth(mytext, `bold ${default_size}vw Open Sans`).toFixed(2);
//console.log("length inside: " + text_Length);
default_size -= 0.01;
//console.log("default_size inside: " + default_size);
}
while (text_Length > width);
setTimeout(function(){
//modify the font size based on text length
upperGuideText.style.fontSize = `${default_size}vw`;
//Append and animate the mytext
upperGuideText.innerHTML = `${mytext}`;
upperGuideText.classList.add("upperGuideAnimeShow");
upperGuideText.classList.remove("upperGuideAnimeHide");
}, 500);
.upperGuideContainer {
position: absolute;
overflow: hidden;
left: 10vw;
top: 48.5vh;
height: 26vh;
width: 82vw;
outline: 0.1vw dashed orange;
}
.upperGuide {
position: absolute;
font-family: 'Open Sans', sans-serif;
font-weight: bold;
color: rgb(128, 128, 128);
left: 0.5vw;
opacity: 0;
margin: 0;
top: 0;
bottom: -16vh;
display: flex;
align-items: center;
}
/*Animations*/
.upperGuideAnimeShow {
animation: upperGuideShow 0.3s ease-in-out;
animation-delay: 0.1s;
animation-fill-mode: forwards ;
}
.upperGuideAnimeHide {
animation: upperGuideHide 0.3s ease-in-out;
animation-fill-mode: forwards ;
}
#-webkit-keyframes upperGuideShow {
0% { opacity: 0; top: 10vh }
100% { opacity: 1; top: -16vh }
}
#-webkit-keyframes upperGuideHide {
from { opacity: 1; top: -16vh }
to { opacity: 0; top: 10vh }
}
<div class = "upperGuideContainer">
<p id="upperGuideText" class="upperGuide"></p>
</div>
The code works and it seems that I'm able to lower the font size when mytext is longer than the container, but for some reason, it doesn't lower the font size enough and we have two line sentences that don't fit in the container.
Note: I want the maximum possible font size that could fit in the container... So I need default_size -= 0.01; intact.
i change the default_size -= 1.0;
//The Text That would be fit into the container
let mytext = 'I was sent to earth to protect you!';
//The function to determine mytext width
function getTextWidth(text, font) {
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
};
//width of the upperGuide container
let width = document.getElementsByClassName("upperGuideContainer")[0].clientWidth;
let text_Length;
let default_size = 5.6;
/* Keep lowering the default font size till the text_Length is smaller than
its container width So that the text can fit in the container */
do {
text_Length = getTextWidth(mytext, `bold ${default_size}vw Open Sans`).toFixed(2);
//console.log("length inside: " + text_Length);
default_size -= 1.0;
//console.log("default_size inside: " + default_size);
}
while (text_Length > width);
setTimeout(function(){
//modify the font size based on text length
upperGuideText.style.fontSize = `${default_size}vw`;
//Append and animate the mytext
upperGuideText.innerHTML = `${mytext}`;
upperGuideText.classList.add("upperGuideAnimeShow");
upperGuideText.classList.remove("upperGuideAnimeHide");
}, 500);
.upperGuideContainer {
position: absolute;
overflow: hidden;
left: 10vw;
top: 48.5vh;
height: 26vh;
width: 82vw;
outline: 0.1vw dashed orange;
}
.upperGuide {
position: absolute;
font-family: 'Open Sans', sans-serif;
font-weight: bold;
color: rgb(128, 128, 128);
left: 0.5vw;
opacity: 0;
margin: 0;
top: 0;
bottom: -16vh;
display: flex;
align-items: center;
}
/*Animations*/
.upperGuideAnimeShow {
animation: upperGuideShow 0.3s ease-in-out;
animation-delay: 0.1s;
animation-fill-mode: forwards ;
}
.upperGuideAnimeHide {
animation: upperGuideHide 0.3s ease-in-out;
animation-fill-mode: forwards ;
}
#-webkit-keyframes upperGuideShow {
0% { opacity: 0; top: 10vh }
100% { opacity: 1; top: -16vh }
}
#-webkit-keyframes upperGuideHide {
from { opacity: 1; top: -16vh }
to { opacity: 0; top: 10vh }
}
<div class = "upperGuideContainer">
<p id="upperGuideText" class="upperGuide"></p>
</div>
Adding white-space: nowrap; to upperGuide class worked like a charm.
The problem was that when text taken more than one line the width didn't change And we should preventing line breaks to make the text width real.
.upperGuide {
position: absolute;
white-space: nowrap;
font-family: 'Open Sans', sans-serif;
font-weight: bold;
color: rgb(128, 128, 128);
left: 0.5vw;
opacity: 0;
margin: 0;
top: 0;
bottom: -16vh;
display: flex;
align-items: center;
}

How to get a canvas relative mouse position of a CSS 3D transformed canvas?

Just for fun I'm trying to draw on 3D transformed canvases. I wrote some code and it kind of works
const m4 = twgl.m4;
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
let count = 0;
canvas.addEventListener('mousemove', (e) => {
const pos = getElementRelativeMousePosition(e, canvas);
ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);
});
});
function getElementRelativeMousePosition(e, elem) {
const pos = convertPointFromPageToNode(elem, e.pageX, e.pageY);
return {
x: pos[0],
y: pos[1],
};
}
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
function convertPointFromPageToNode(elem, pageX, pageY) {
const mat = m4.inverse(getTransformationMatrix(elem));
return m4.transformPoint(mat, [pageX, pageY, 0]);
};
function getTransformationMatrix(elem) {
let matrix = m4.identity();
let currentElem = elem;
while (currentElem !== undefined &&
currentElem !== currentElem.ownerDocument.documentElement) {
const style = window.getComputedStyle(currentElem);
const localMatrix = parseMatrix(style.transform);
matrix = m4.multiply(localMatrix, matrix);
currentElem = currentElem.parentElement;
}
const w = elem.offsetWidth;
const h = elem.offsetHeight;
let i = 4;
let left = +Infinity;
let top = +Infinity;
for (let i = 0; i < 4; ++i) {
const p = m4.transformPoint(matrix, [w * (i & 1), h * ((i & 2) >> 1), 0]);
left = Math.min(p[0], left);
top = Math.min(p[1], top);
}
const rect = elem.getBoundingClientRect()
document.querySelector('p').textContent =
`${w}x${h}`;
matrix = m4.multiply(m4.translation([
window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top,
0]), matrix);
return matrix;
}
function parseMatrix(str) {
if (str.startsWith('matrix3d(')) {
return str.substring(9, str.length - 1).split(',').map(v => parseFloat(v.trim()));
} else if (str.startsWith('matrix(')) {
const m = str.substring(7, str.length - 1).split(',').map(v => parseFloat(v.trim()));
return [
m[0], m[1], 0, 0,
m[2], m[3], 0, 0,
0, 0, 1, 0,
m[4], m[5], 0, 1,
]
} else if (str == 'none') {
return m4.identity();
}
throw new Error('unknown format');
}
canvas {
display: block;
background: yellow;
transform: scale(0.75);
}
#c1 {
margin: 20px;
background: red;
transform: translateX(-50px);
display: inline-block;
}
#c2 {
margin: 20px;
background: green;
transform: rotate(45deg);
display: inline-block;
}
#c3 {
margin: 20px;
background: blue;
display: inline-block;
}
#c4 {
position: absolute;
top: 0;
background: cyan;
transform: translateX(-250px) rotate(55deg);
display: inline-block;
}
#c5 {
background: magenta;
transform: translate(50px);
display: inline-block;
}
#c6 {
background: pink;
transform: rotate(45deg);
display: inline-block;
}
<p>
foo
</p>
<div id="c1">
<div id="c2">
<div id="c3">
<canvas></canvas>
</div>
</div>
</div>
<div id="c4">
<div id="c5">
<div id="c6">
<canvas></canvas>
</div>
</div>
</div>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
The code above works. Move the mouse over either of the yellow canvas elements and you'll see it draws correctly.
But, as soon as I add some 3D transform it fails.
Change the CSS for '#c6' to
#c6 {
background: pink;
transform: rotate(45deg) rotateX(45deg); /* changed */
display: inline-block;
}
and now when I draw over the right yellow canvas things are off.
const m4 = twgl.m4;
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
let count = 0;
canvas.addEventListener('mousemove', (e) => {
const pos = getElementRelativeMousePosition(e, canvas);
ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);
});
});
function getElementRelativeMousePosition(e, elem) {
const pos = convertPointFromPageToNode(elem, e.pageX, e.pageY);
return {
x: pos[0],
y: pos[1],
};
}
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
function convertPointFromPageToNode(elem, pageX, pageY) {
const mat = m4.inverse(getTransformationMatrix(elem));
return m4.transformPoint(mat, [pageX, pageY, 0]);
};
function getTransformationMatrix(elem) {
let matrix = m4.identity();
let currentElem = elem;
while (currentElem !== undefined &&
currentElem !== currentElem.ownerDocument.documentElement) {
const style = window.getComputedStyle(currentElem);
const localMatrix = parseMatrix(style.transform);
matrix = m4.multiply(localMatrix, matrix);
currentElem = currentElem.parentElement;
}
const w = elem.offsetWidth;
const h = elem.offsetHeight;
let i = 4;
let left = +Infinity;
let top = +Infinity;
for (let i = 0; i < 4; ++i) {
const p = m4.transformPoint(matrix, [w * (i & 1), h * ((i & 2) >> 1), 0]);
left = Math.min(p[0], left);
top = Math.min(p[1], top);
}
const rect = elem.getBoundingClientRect()
document.querySelector('p').textContent =
`${w}x${h}`;
matrix = m4.multiply(m4.translation([
window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top,
0]), matrix);
return matrix;
}
function parseMatrix(str) {
if (str.startsWith('matrix3d(')) {
return str.substring(9, str.length - 1).split(',').map(v => parseFloat(v.trim()));
} else if (str.startsWith('matrix(')) {
const m = str.substring(7, str.length - 1).split(',').map(v => parseFloat(v.trim()));
return [
m[0], m[1], 0, 0,
m[2], m[3], 0, 0,
0, 0, 1, 0,
m[4], m[5], 0, 1,
]
} else if (str == 'none') {
return m4.identity();
}
throw new Error('unknown format');
}
canvas {
display: block;
background: yellow;
transform: scale(0.75);
}
#c1 {
margin: 20px;
background: red;
transform: translateX(-50px);
display: inline-block;
}
#c2 {
margin: 20px;
background: green;
transform: rotate(45deg);
display: inline-block;
}
#c3 {
margin: 20px;
background: blue;
display: inline-block;
}
#c4 {
position: absolute;
top: 0;
background: cyan;
transform: translateX(-250px) rotate(55deg);
display: inline-block;
}
#c5 {
background: magenta;
transform: translate(50px);
display: inline-block;
}
#c6 {
background: pink;
transform: rotate(45deg) rotateX(45deg);
display: inline-block;
}
<p>
foo
</p>
<div id="c1">
<div id="c2">
<div id="c3">
<canvas></canvas>
</div>
</div>
</div>
<div id="c4">
<div id="c5">
<div id="c6">
<canvas></canvas>
</div>
</div>
</div>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
Any ideas what I'm doing wrong?
Note: That's just a complementary answer on what OP already did find by themselves.
You can actually make this all work by using the MouseEvent constructor.
You can pass the clientX and clientY properties of this Event inside the constructor (or pageX & pageY if you prefer), then dispatching this composed event to your target will set its offsetX and offsetY properties relative to the target.
Since dispatchEvent does fire the Event synchronously, we can even make a converter:
const init_pos = { x: 50, y: 50};
const relative_pos = {};
const canvas = document.querySelector('canvas');
canvas.addEventListener('mousemove', e => {
relative_pos.x = e.offsetX;
relative_pos.y = e.offsetY;
}, {once: true});
canvas.dispatchEvent(new MouseEvent('mousemove', {
clientX: init_pos.x,
clientY: init_pos.y
}));
// synchronously log
console.log(relative_pos);
canvas {
display: block;
background: yellow;
transform: scale(0.75);
}
#c4 {
position: absolute;
top: 0;
background: cyan;
transform: translateX(-250px) rotate(55deg);
display: inline-block;
}
#c5 {
background: magenta;
transform: translate(50px);
display: inline-block;
}
#c6 {
background: pink;
transform: rotate(45deg);
display: inline-block;
}
<div id="c4">
<div id="c5">
<div id="c6">
<canvas></canvas>
</div>
</div>
</div>
Now, given the example in your own answer, you may want to actually hold a single object that will keep the global Event's position, and to get the relative positions of your canvas at every frame in a requestAnimationFrame loop.
However, this setup will obviously traverse your canvases, if you want only the visible face to handle the events, then you'd have to check which one matches document.elementFromPoint(x, y), which itself needs your elements to react to pointer-events.
// will hold our last event's position
const pos = {
x: 0,
y: 0
};
const canvases = document.querySelectorAll('canvas');
// A single global "real" MouseEvent handler
document.body.onmousemove = (e) => {
pos.x = e.clientX;
pos.y = e.clientY;
};
canvases.forEach(canvas => {
const ctx = canvas.getContext('2d');
let count = 0;
canvas.addEventListener('mousemove', draw);
function draw(e) {
// do not fire on real Events
if (e.cancelable) return;
const x = e.offsetX * canvas.width / canvas.clientWidth;
const y = e.offsetY * canvas.height / canvas.clientHeight;
if (x < 0 || x > canvas.width || y < 0 || y > canvas.height) {
return;
}
ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
ctx.fillRect(x - 1, y - 1, 3, 3);
}
});
anim();
function anim() {
requestAnimationFrame(anim);
// in case we want to paint only on the front element
const front_elem = single_face.checked && document.elementFromPoint(pos.x, pos.y);
// at every frame
canvases.forEach(c => {
if (!front_elem || c === front_elem) {
// force a composed event (synchronously, so we are still in rAF callback)
c.dispatchEvent(
new MouseEvent('mousemove', {
clientX: pos.x,
clientY: pos.y
})
);
}
});
}
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
.scene {
width: 200px;
height: 200px;
perspective: 600px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation-duration: 16s;
animation-name: rotate;
animation-iteration-count: infinite;
animation-timing-function: linear;
pointer-events: none; /* no need for mouse events */
}
#single_face:checked+.scene .cube {
pointer-events: all; /* except if we want to find out who is the front one */
}
label,#single_face {float: right}
#keyframes rotate {
from {
transform: translateZ(-100px) rotateX( 0deg) rotateY( 0deg);
}
to {
transform: translateZ(-100px) rotateX(360deg) rotateY(720deg);
}
}
.cube__face {
position: absolute;
width: 200px;
height: 200px;
display: block;
}
.cube__face--front {
background: rgba(255, 0, 0, 0.2);
transform: rotateY( 0deg) translateZ(100px);
}
.cube__face--right {
background: rgba(0, 255, 0, 0.2);
transform: rotateY( 90deg) translateZ(100px);
}
.cube__face--back {
background: rgba(0, 0, 255, 0.2);
transform: rotateY(180deg) translateZ(100px);
}
.cube__face--left {
background: rgba(255, 255, 0, 0.2);
transform: rotateY(-90deg) translateZ(100px);
}
.cube__face--top {
background: rgba(0, 255, 255, 0.2);
transform: rotateX( 90deg) translateZ(100px);
}
.cube__face--bottom {
background: rgba(255, 0, 255, 0.2);
transform: rotateX(-90deg) translateZ(100px);
}
<label>Draw on a single face</label><input type="checkbox" id="single_face">
<div class="scene">
<div class="cube">
<canvas class="cube__face cube__face--front"></canvas>
<canvas class="cube__face cube__face--back"></canvas>
<canvas class="cube__face cube__face--right"></canvas>
<canvas class="cube__face cube__face--left"></canvas>
<canvas class="cube__face cube__face--top"></canvas>
<canvas class="cube__face cube__face--bottom"></canvas>
</div>
</div>
<pre id="debug"></pre>
Sigh ... not the definitive answer yet but apparently event.offsetX and event.offsetY are supposed to be this value even though according to MDN they are not standard yet.
Testing it seems to work in both Chrome and Firefox. Safari is off though in some tests. Also unfortunately offsetX and offsetY do not exist on touch events. They do exist on pointer events but pointer events are not supported by Safari as of 2019/05
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
let count = 0;
canvas.addEventListener('mousemove', (e) => {
const pos = {
x: e.offsetX * ctx.canvas.width / ctx.canvas.clientWidth,
y: e.offsetY * ctx.canvas.height / ctx.canvas.clientHeight,
};
ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);
});
});
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
canvas {
display: block;
background: yellow;
transform: scale(0.75);
}
#c1 {
margin: 20px;
background: red;
transform: translateX(-50px);
display: inline-block;
}
#c2 {
margin: 20px;
background: green;
transform: rotate(45deg);
display: inline-block;
}
#c3 {
margin: 20px;
background: blue;
display: inline-block;
}
#c4 {
position: absolute;
top: 0;
background: cyan;
transform: translateX(-250px) rotate(55deg);
display: inline-block;
}
#c5 {
background: magenta;
transform: translate(50px);
display: inline-block;
}
#c6 {
background: pink;
transform: rotate(45deg) rotateX(45deg); /* changed */
display: inline-block;
}
<p>
foo
</p>
<div id="c1">
<div id="c2">
<div id="c3">
<canvas></canvas>
</div>
</div>
</div>
<div id="c4">
<div id="c5">
<div id="c6">
<canvas></canvas>
</div>
</div>
</div>
Unfortunately we still have the issue that sometimes we want a canvas relative position outside of an event. In the example below we'd like to keep drawing under the mouse pointer even when the pointer is not moving.
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;
function draw(e, radius = 1) {
const pos = {
x: e.offsetX * ctx.canvas.width / ctx.canvas.clientWidth,
y: e.offsetY * ctx.canvas.height / ctx.canvas.clientHeight,
};
document.querySelector('#debug').textContent = count;
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
ctx.fill();
}
function preventDefault(e) {
e.preventDefault();
}
if (window.PointerEvent) {
canvas.addEventListener('pointermove', (e) => {
draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
});
canvas.addEventListener('touchstart', preventDefault, {passive: false});
canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mousedown', preventDefault);
}
});
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
.scene {
width: 200px;
height: 200px;
perspective: 600px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation-duration: 16s;
animation-name: rotate;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
#keyframes rotate {
from { transform: translateZ(-100px) rotateX( 0deg) rotateY( 0deg); }
to { transform: translateZ(-100px) rotateX(360deg) rotateY(720deg); }
}
.cube__face {
position: absolute;
width: 200px;
height: 200px;
display: block;
}
.cube__face--front { background: rgba(255, 0, 0, 0.2); transform: rotateY( 0deg) translateZ(100px); }
.cube__face--right { background: rgba(0, 255, 0, 0.2); transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back { background: rgba(0, 0, 255, 0.2); transform: rotateY(180deg) translateZ(100px); }
.cube__face--left { background: rgba(255, 255, 0, 0.2); transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top { background: rgba(0, 255, 255, 0.2); transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { background: rgba(255, 0, 255, 0.2); transform: rotateX(-90deg) translateZ(100px); }
<div class="scene">
<div class="cube">
<canvas class="cube__face cube__face--front"></canvas>
<canvas class="cube__face cube__face--back"></canvas>
<canvas class="cube__face cube__face--right"></canvas>
<canvas class="cube__face cube__face--left"></canvas>
<canvas class="cube__face cube__face--top"></canvas>
<canvas class="cube__face cube__face--bottom"></canvas>
</div>
</div>
<pre id="debug"></pre>

Translation of time to keyframe animation percentages

I'm working on an animation and I'm trying to understand how keyframes fit into it.
I want to show an element for 3 seconds, fade out for 1 second, wait for 3 seconds, fade in for 1 second, be visible for 3 seconds. So a total of 8 seconds (3 + 1 + 3 + 1).
I don't know how to write that as keyframes. I have alternate set in my animation since it's using percentages. Here is what I have so far:
time = 0;
window.addEventListener("load", function() {
setInterval(function() {
var label = document.getElementById("label");
if (time==0) {
label.innerHTML = ++time;
}
else {
label.innerHTML = ++time;
}
if (time>=8) time = 0;
}, 1000);
})
* {
margin: 0;
padding: 0;
font-family:sans-serif;
}
#Icons_A0 {
position: absolute;
box-sizing: border-box;
transform: translateX(-50%) translateY(-50%);
left: 50%;
top: 50%;
border: 1px solid #A1A1A1;
background: #E5E5E5;
width: 234px;
height: 238px;
background-color: rgba(255,255,255,1);
overflow: hidden;
opacity: 1;
}
#Rectangle_175 {
opacity: 1;
fill: rgba(75,134,193,1);
stroke: rgb(84, 75, 193);
stroke-width: 4px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Rectangle_175 {
position: absolute;
overflow: visible;
width: 134.35028076171875px;
height: 134.3502655029297px;
left: 49.825px;
top: 76.825px;
transform: rotate(45deg);
transform-origin: left;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180,180,180,1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
animation: fadein 8s linear 0s infinite alternate;
}
#keyframes fadein {
0% {
opacity: 1;
}
20% {
opacity: 1;
}
30% {
opacity: 0;
}
60% {
opacity: 0;
}
70% {
opacity: 1;
}
100% {
opacity: 1;
}
}
<div id="Icons_A0">
<svg data-name="Rectangle 175" data-type="Rectangle" class="Rectangle_175">
<rect id="Rectangle_175" rx="0" ry="0" x="0" y="0" width="120" height="70">
</rect>
</svg>
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<span id="label"></span>
</div>
If I understand your question correctly, then this can be achieved via the following key frame set:
#keyframes fadein {
0% {
opacity: 1;
}
37.5% {
/* 3 / 8 */
opacity: 1;
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
}
100% {
opacity: 1;
}
}
The comments show how the percentages for different key frames are calculated based on your requirements. The other key change to make is to remove the alternate behaviour from your animation rule, to ensure the animation cycle repeats in a consistent fashion as required:
/* remove alternate */
animation: fadein 8s linear 0s infinite;
Here's a stripped down copy of your code to isolate the animated circle:
function animationListener(event) {
var type = event.type;
var label = type;
if (type=="animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 1000);
intervalFunction();
label = "iteration";
}
else if (type=="animationstart") {
label = "start";
}
else if (type=="animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var time = new Date().getTime();
app.timeLabel.innerHTML = Math.round((time - app.startTime)/1000);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};
* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
/* remove alternate */
animation: fadein 8s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
align-items: center;
}
label {
width: 80px;
display: inline-block;
}
#keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<div id="container">
<label>time: </label>
<span id="timeLabel"></span>
<br>
<label>state: </label>
<span id="stateLabel"></span>
<br>
<label>key frame: </label>
<span id="keyframeLabel"></span>
</div>
If your total length is 8s, and you just need to translate that to percentages the math is pretty simple:
100/8=12.5
So, your keyframes would come in at:
1 sec : 12.5 * 1 = 12.5%
4 sec : 12.5 * 4 = 50%
7 sec : 12.5 * 7 = 87.5%
8 sec : 12.5 * 8 = 100%
Adding #DacreDenny's answer here so I can modify it and add notes.
function animationListener(event) {
var type = event.type;
var label = type;
if (type=="animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 15);
intervalFunction();
label = "iteration";
}
else if (type=="animationstart") {
label = "start";
}
else if (type=="animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var currentTime = new Date().getTime();
var time = (currentTime - app.startTime)/1000;
var duration = parseFloat(window.getComputedStyle(app.ellipse).animationDuration);
var maxValue = 100;
var position = ((time * maxValue)/duration);
app.timeLabel.innerHTML = Math.round(time);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
app.timelineRange.value = position;
app.positionLabel.innerHTML = Math.round(position) + "%";
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.timelineRange = document.getElementById("timelineRange");
app.positionLabel = document.getElementById("positionLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};
* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
#keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 50px;
height: 50px;
left: 20px;
top: 50px;
/* remove alternate */
animation: fadein 4s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
}
label {
width: 80px;
display: inline-block;
}
input[type=range] {
outline: 0px solid red;
display: block;
width: 90%;
margin-left: 0;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: rgb(255,255,255);
}
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<div id="container">
<input id="timelineRange" type="range" value="0" min="0" max="100">
<br>
<label>time: </label>
<span id="timeLabel"></span>
<br>
<label>position: </label>
<span id="positionLabel"></span>
<br>
<label>state: </label>
<span id="stateLabel"></span>
<br>
<label>key frame: </label>
<span id="keyframeLabel"></span>
<br>
<br>
</div>

Rotating a cube around its center Y axis, works first time

I've made a cube with html/css.
The first time I apply a rotation transformation the cube rotates very nicely in place around its center Y axis.
The second time however, the cube kind of "comes forward" and then "moves back" while rotating. The cube ends up in the same position, but the transition is different.
#wrapper {
-webkit-perspective: 1100px;
-webkit-perspective-origin: 50% 300px;
perspective: 1100px;
perspective-origin: 50% 300px;
margin-top: 25px;
}
#cube {
position: relative;
margin: 0 auto;
height: 1150px;
width: 1150px;
-webkit-transform-style: preserve-3d;
-webkit-transition: all 2s ease;
transform-style: preserve-3d;
transition: all 2s ease;
transform: translateZ(-100000px);
}
.face {
position: absolute;
height: 1140px;
width: 1140px;
padding: 20px;
background-color: white;
border: solid 1px black;
}
#cube .one {
transform: translateZ(600px);
}
#cube .two {
transform: rotateY(90deg) translateZ(600px);
}
#cube .three {
transform: rotateY(180deg) translateZ(600px);
}
#cube .four {
transform: rotateY(-90deg) translateZ(600px);
}
#cube .five {
transform: rotateX(-90deg) translateZ(600px) rotate(180deg);
}
#cube .six {
transform: rotateX(90deg) translateZ(600px);
}
Bit of Javascript to move to cube into a good view
$("#cube").css("transform", "translateZ(-2500px) translateX(-380px)");
JavaScript to Apply Rotation
if (direction == "left") {
if (face == 1) {
angle = angle + 90;
$("#cube").css("transform", "rotateY(" + angle + "deg) translateX(2500px) translateZ(-380px)");
face++;
}
else if (face == 2) {
angle = angle + 90;
$("#cube").css("transform", "rotateY(" + angle + "deg) translateZ(2500px) translateX(380px) ");
face++;
}
else if (face == 3) {
angle = angle + 90;
$("#cube").css("transform", "rotateY(" + angle + "deg) translateX(-2500px) translateZ(380px) ");
face++;
}
else if (face == 4) {
angle = angle + 90;
$("#cube").css("transform", "rotateY(" + angle + "deg) translateZ(-2500px) translateX(-380px) ");
face = 1;
}
}
I think you have different width on your cube panels!! you have fixed width in css but paddings increase outer width.
check to see if they all have the same width with your inspect element. try working around box-sizing.

Activate CSS 3d transforms when element scrolls into viewport

I am trying to activate this small CSS animation involving CSS 3d transforms, when each of the elements scroll into view. The laptops need to open and close when scrolled into position. Is there any way this can be done using only CSS? If not Jquery answers will also be helpful!
The code is below.
/* Css Code */
.macbook {
width: 300px;
margin: 50px auto;
-webkit-perspective: 750;
-webkit-perspective-origin: 50% bottom;
-webkit-transform-style: preserve-3d;
-moz-perspective: 750px;
-moz-perspective-origin: 50% bottom;
-moz-transform-style: preserve-3d;
perspective: 750;
perspective-origin: 50% bottom;
transform-style: preserve-3d;
}
.macbook-lid {
width: 80%;
margin: 0 auto;
-webkit-transform-origin: 50% bottom;
-webkit-transform-style: preserve-3d;
-moz-transform-origin: 50% bottom;
-moz-transform-style: preserve-3d;
transform-origin: 50% bottom;
transform-style: preserve-3d;
-webkit-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
}
.macbook-lid:before {
display: block;
content: '';
width: 92%;
margin: 0 auto;
padding: 2% 3% 0 3%;
background-color: #D3D1D2;
border-radius: 10px 10px 0 0;
-webkit-transform-origin: 50% bottom;
-webkit-transform: rotate3d(1, 0, 0, 90deg);
-moz-transform-origin: 50% bottom;
-moz-transform: rotate3d(1, 0, 0, 90deg);
transform-origin: 50% bottom;
transform: rotate3d(1, 0, 0, 90deg);
-webkit-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
}
.macbook-screen {
position: relative;
background-color: #353535;
margin: 0 auto;
padding: 3%;
border-radius: 5px 5px 0 0;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
}
.macbook-screen:before {
display: block;
content: '';
position: absolute;
top: 2%;
left: 49%;
width: 1%;
padding-top: 1%;
background-color: #000;
}
.macbook-content {
position: relative;
overflow: hidden;
box-shadow: inset 0px 0px 6px #222;
}
.macbook-content1 {
background-image: url("../img/cs.png");
}
.macbook-content2 {
background-image: url("../img/xyz.png");
}
.macbook-content3 {
background-image: url("../img/abc.png");
}
.macbook-content4 {
background-image: url("../img/def.png");
}
.macbook-content5 {
background-image: url("../img/ghi.png");
}
.macbook-content6 {
background-image: url("../img/jkl.png");
}
.macbook-content:before {
display: block;
content: '';
width: 1px;
padding-top: 60%;
float: left;
}
.macbook-content:after {
display: block;
content: '';
clear: both;
}
.macbook:not(:hover) .macbook-lid {
-webkit-transform: rotate3d(-1, 0, 0, 91deg);
-moz-transform: rotate3d(-1, 0, 0, 91deg);
transform: rotate3d(-1, 0, 0, 91deg);
}
.macbook:not(:hover) .macbook-lid:before {
width: 94%;
}
<div class="row">
<div class="col-md-3">
<div class="macbook">
<div class="macbook-lid">
<div class="macbook-screen">
<div class="macbook-content macbook-content1">
</div>
</div>
</div>
<div class="macbook-base"></div>
</div>
</div>
<div class="col-md-9">
<div class="website-description text-content-yellow">
<h1>EYE- Name</h1>
<p>Description</p>
</div>
</div>
</div>
There is no way to do this via CSS only.
But you can acompilsh this easily via Waypoints library
var waypoint = new Waypoint({
element: document.getElementById('yourElement'),
handler: function(direction) {
console.log('Scrolled to waypoint!');
}
})
or with jQuery
var waypoints = $('.col-md-3').waypoint({
handler: function(direction) {
$('.col-md-3').addClass('inview');
}
})
Edit
But, for the sake of education, here is a solution built from scratch, library agnostic, easy to use.
var getPoints = function($el, wt){
return (wt > ($el.offset().top - ($(window).height()/2)) && wt < (($el.offset().top) + $el.height()));
}
var cm = function checkMilestones() {
var wt = $(window).scrollTop();
if(getPoints($('.col-md-3'), wt)){
//check if your element is in view
$('.col-md-3').addClass('inview');
} else if (getPoints($('.col-md-9'), wt)){
//if your another element is in view
$('.col-md-9').addClass('inview');
}
};
$(document).on('ready', cm);
$(window).on('scroll', cm);
Implementing
In your case, you should do this:
instead of :not(:hover), use a class
.macbook.closed .macbook-lid {
-webkit-transform: rotate3d(-1, 0, 0, 91deg);
-moz-transform: rotate3d(-1, 0, 0, 91deg);
transform: rotate3d(-1, 0, 0, 91deg);
}
Put this class in your div
<div class="macbook closed">
And use your js like this:
var getPoints = function($el, wt){
return (wt > ($el.offset().top - ($(window).height()/2)) && wt < (($el.offset().top) + $el.height()));
}
var cm = function checkMilestones() {
var wt = $(window).scrollTop();
if(getPoints($('.macbook'), wt)){
//check if your element is in view
$('.macbook').removeClass('closed');
} else if (getPoints($('.anotherElement'), wt)){
//if your another element is in view
$('.anotherElement').removeClass('removeClass');
}
};
$(document).on('ready', cm);
$(window).on('scroll', cm);
This seems to work. I've added separate classes for the 7 separate elements on display
$(window).scroll(function () {
$('.macbook').each(function () {
var imagePos = $(this).offset().top;
var imageHeight = $(this).height();
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-1");
} else {
$(this).addClass("macbook-1");
}
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-2");
} else {
$(this).addClass("macbook-2");
}
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-3");
} else {
$(this).addClass("macbook-3");
}
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-4");
} else {
$(this).addClass("macbook-4");
}
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-5");
} else {
$(this).addClass("macbook-5");
}
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-6");
} else {
$(this).addClass("macbook-6");
}
if (imagePos < topOfWindow + imageHeight && imagePos + imageHeight > topOfWindow) {
$(this).removeClass("macbook-7");
} else {
$(this).addClass("macbook-7");
}
});
});

Categories