I have a function which increments the css quality of the position of a div layer and need it to stop when it reaches a certain amount of percentage to either the right or left (depending on the layer).
I have tried to do an if statement with a greater than operator, but does not seem to work. Here is the code in full:
<html>
<head>
<title>Stelucir</title>
<style>
body {
background-color: white;
}
#bg-right {
background-color: black;
position: fixed;
top: 0;
bottom: 0;
left: 50%;
right: 0;
z-index: -1;
}
</style>
<script type="text/javascript">
var header = null; // object
var about = null; // object
var blog = null; // object
var forum = null; // object
var chat = null; // object
var home = null; // object
function doMove() {
header.style.right = parseInt(header.style.right)+1+'%';
about.style.left = parseInt(about.style.left)+1+'%';
blog.style.right = parseInt(blog.style.right)+1+'%';
forum.style.left = parseInt(forum.style.left)+1+'%';
chat.style.right = parseInt(chat.style.right)+1+'%';
home.style.left = parseInt(home.style.left)+1+'%';
setTimeout(doMove,30); // call doMove in 20msec
}
function init() {
header = document.getElementById('header');
about = document.getElementById('about');
blog = document.getElementById('blog');
forum = document.getElementById('forum');
chat = document.getElementById('chat');
home = document.getElementById('home');
doMove(); // start animating
}
window.onload = init;
</script>
</head>
<body>
<div id="bg-right"></div>
<div id="header" style = "position:absolute;right:25%;font-size:80px;">Stelucir</div>
<div id="about" style = "position:absolute;left:40%;font- size:40px;top:90px;color:white;">About</div>
<div id="blog" style = "position:absolute;right:40%;font-size:40px;top:130px;">Blog</div>
<div id="forum" style = "position:absolute;left:40%;font-size:40px;top:170px;color:white;">Forum</div>
<div id="chat" style = "position:absolute;right:40%;font-size:40px;top:210px;">Chat</div>
<div id="home" style = "position:absolute;left:40%;font-size:40px;top:250px;color:white;">Home</div>
</body>
</html>
Use a global boolean. Start it at true, and when it reaches whatever point you want, set it to false. In doMove check to see that this is true, and if it's false simply return.
setTimeout() returns a handle on the timer. you can then call clearTimeout() on this handle to stop the timer.
Make a global variable to store this
var timer = null;
...
function doMove() {
...
timer = setTimeout(...);
}
//somewhere else
clearTimeout(timer);
I would more suggest using an interval instead of multiple setTimeout call. Also both setInterval and setTimeout return a reference which can be used to stop them using clearInterval(ref) or clearTimeout(ref);
Here is a little fiddle that animate a box to the right and stop when it is there.
http://jsfiddle.net/JV35w/1/
var elem = document.getElementById('foo'),
startX = 0,
endX = 400,
move = function() {
elem.style.left = startX + 'px';
startX += 10;
if (endX === startX) {
startX = 0;
clearInterval(t);
};
},
doMove = function() {
t = setInterval(move);
},
t;
doMove();
https://developer.mozilla.org/en/DOM/window.setTimeout
https://developer.mozilla.org/en/DOM/window.setInterval
Related
I want to show an image but still I can't manage to make it works. Respective parts I need are there like.
function mouseIn() {
$('.img').addClass('show');
}
function mouseOut() {
$('.img').removeClass('show');
}
$('.hover-me').hover(mouseIn, mouseOut);
.img {
display: none;
}
.img.show {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p class="hover-me">Hi</p>
<img src="https://picsum.photos/150" class="img">
This script takes the .trg class elements that are in the packaging element id="wrap". When you hold the mouse over some target elements it starts to run time (I have currently set 500ms). The time is set to the variable var delay = 500. When this time expires, the script takes the data attribute of the target element and creates a new element img. When you remove the mouse cursor from the target element, all elements with class .img are removed... thus the created image is removed.
For site optimization, this method is better because you will not load content that is invisible... but you will create it when needed.
With small adjustments to my code, you can change it to add a class to an existing element or work in another way that works for you.
Example:
$(document).ready(function () {
var delay = 500; // <-- delay time in ms
var wrp = '#wrap';
var mouseMove;
var url;
var el;
var show = true;
$(wrp + ' .trg').on('mouseenter', function () {
mouseMove = new Date().getTime();
show = true;
el = this;
url = $(this).attr('data');
});
$(wrp + ' .trg').on('mouseout', function () {
$('.img').remove();
});
setInterval(function () {
var curTime = new Date().getTime();
if (curTime - mouseMove > delay && $(wrp + ':hover').length != 0 && show) {
var img = document.createElement('img');
img.setAttribute('class', 'img');
img.setAttribute('src', url);
el.append(img);
show = false;
}
}, delay);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="wrap">
<div class="trg" data="https://blog.54ka.org/wp-content/uploads/2020/08/horses-on-summer-meadow_027_by_54ka-165x165.jpg">Lorem 01</div>
<div class="trg" data="https://blog.54ka.org/wp-content/uploads/2020/08/horses-on-summer-meadow_005_by_54ka-165x165.jpg">Lorem 02</div>
<div class="trg" data="https://blog.54ka.org/wp-content/uploads/2020/08/horses-on-summer-meadow_006_by_54ka-165x165.jpg">Lorem 03</div>
</div>
Example 2
This example is based on your code
$(document).ready(function () {
var delay = 500; // <-- delay time in ms
var wrp = '.hover-me';
var mouseMove;
var show = true;
$(wrp).on('mouseenter', function () {
mouseMove = new Date().getTime();
show = true;
});
$(wrp).on('mouseout', function () {
$('.img').removeClass('show');
});
setInterval(function () {
var curTime = new Date().getTime();
if (curTime - mouseMove > delay && $(wrp + ':hover').length != 0 && show) {
$('.img').addClass('show');
show = false;
}
}, delay);
});
.img {
display: none;
}
.show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<p class="hover-me">Hi</p>
<img src="https://picsum.photos/150" class="img">
Right now I have a lovely code (that was initially for flowing snowflakes) that lets cloned divs fall from the top of the window, to the bottom and repeat. The thing is that I want the content to change on click. However, this is not yet working.
I know how to change content of a div without it being cloned, but I have serious trouble figuring out how to do the same with one div being cloned within the code.
Anyone have any tips what I should do, even a hint in which direction to go. I'm clueless.
This is the fiddle:
http://jsfiddle.net/4yaxvt7h/
the javascript:
function changeImage(){
document.getElementById('toChange').src='https://i.pinimg.com/originals/6e/19/56/6e195649034f042d1dea5230234570a8.gif';
}
// Array to store our Snowflake objects
var snowflakes = [];
// Global variables to store our browser's window size
var browserWidth;
var browserHeight;
// Specify the number of snowflakes you want visible
var numberOfSnowflakes = 15;
// Flag to reset the position of the snowflakes
var resetPosition = false;
// Handle accessibility
var enableAnimations = false;
var reduceMotionQuery = matchMedia("(prefers-reduced-motion)");
// Handle animation accessibility preferences
function setAccessibilityState() {
if (reduceMotionQuery.matches) {
enableAnimations = false;
} else {
enableAnimations = true;
}
}
setAccessibilityState();
reduceMotionQuery.addListener(setAccessibilityState);
//
// It all starts here...
//
function setup() {
if (enableAnimations) {
window.addEventListener("DOMContentLoaded", generateSnowflakes, false);
window.addEventListener("resize", setResetFlag, false);
}
}
setup();
//
// Constructor for our Snowflake object
//
function Snowflake(element, speed, xPos, yPos) {
// set initial snowflake properties
this.element = element;
this.speed = speed;
this.xPos = xPos;
this.yPos = yPos;
this.scale = 1;
// declare variables used for snowflake's motion
this.counter = 0;
this.sign = Math.random() < 0.5 ? 1 : -1;
// setting an initial opacity and size for our snowflake
this.element.style.opacity = 1;
}
//
// The function responsible for actually moving our snowflake
//
Snowflake.prototype.update = function () {
// using some trigonometry to determine our x and y position
this.counter += this.speed / 5000;
this.xPos += this.sign * this.speed * Math.cos(this.counter) / 40;
this.yPos += Math.sin(this.counter) / 40 + this.speed / 30;
this.scale = .5 + Math.abs(10 * Math.cos(this.counter) / 20);
// setting our snowflake's position
setTransform(Math.round(this.xPos), Math.round(this.yPos), this.scale, this.element);
// if snowflake goes below the browser window, move it back to the top
if (this.yPos > browserHeight) {
this.yPos = -50;
}
}
//
// A performant way to set your snowflake's position and size
//
function setTransform(xPos, yPos, scale, el) {
el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0) scale(${scale}, ${scale})`;
}
//
// The function responsible for creating the snowflake
//
function generateSnowflakes() {
// get our snowflake element from the DOM and store it
var originalSnowflake = document.querySelector(".snowflake");
// access our snowflake element's parent container
var snowflakeContainer = originalSnowflake.parentNode;
snowflakeContainer.style.display = "block";
// get our browser's size
browserWidth = document.documentElement.clientWidth;
browserHeight = document.documentElement.clientHeight;
// create each individual snowflake
for (var i = 0; i < numberOfSnowflakes; i++) {
// clone our original snowflake and add it to snowflakeContainer
var snowflakeClone = originalSnowflake.cloneNode(true);
snowflakeContainer.appendChild(snowflakeClone);
// set our snowflake's initial position and related properties
var initialXPos = getPosition(50, browserWidth);
var initialYPos = getPosition(50, browserHeight);
var speed = 5 + Math.random() * 40;
// create our Snowflake object
var snowflakeObject = new Snowflake(snowflakeClone,
speed,
initialXPos,
initialYPos);
snowflakes.push(snowflakeObject);
}
// remove the original snowflake because we no longer need it visible
snowflakeContainer.removeChild(originalSnowflake);
moveSnowflakes();
}
//
// Responsible for moving each snowflake by calling its update function
//
function moveSnowflakes() {
if (enableAnimations) {
for (var i = 0; i < snowflakes.length; i++) {
var snowflake = snowflakes[i];
snowflake.update();
}
}
// Reset the position of all the snowflakes to a new value
if (resetPosition) {
browserWidth = document.documentElement.clientWidth;
browserHeight = document.documentElement.clientHeight;
for (var i = 0; i < snowflakes.length; i++) {
var snowflake = snowflakes[i];
snowflake.xPos = getPosition(50, browserWidth);
snowflake.yPos = getPosition(50, browserHeight);
}
resetPosition = false;
}
requestAnimationFrame(moveSnowflakes);
}
//
// This function returns a number between (maximum - offset) and (maximum + offset)
//
function getPosition(offset, size) {
return Math.round(-1 * offset + Math.random() * (size + 2 * offset));
}
//
// Trigger a reset of all the snowflakes' positions
//
function setResetFlag(e) {
resetPosition = true;
}
html
<div id="snowflakeContainer">
<div class="snowflake"><img src="element1.png"
</div>
css
body{
background-color: black;
}
#snowflakeContainer {
position: absolute;
left: 0px;
top: 0px;
display: none;
}
.snowflake {
position: fixed;
background-color: red;
user-select: none;
z-index: 1000;
pointer-events: none;
border-radius: 50%;
width: 200px;
height: 200px;
}
img{
max-width: 100%;
}
any tips are super welcome!!
You have several different problems here. First, your CSS sets pointer-events: none; for all .snowflake elements. This will stop any clicks from triggering, so you have to remove it if you want mouse interactivity.
Second, your changeImage() function uses document.getElementById('toChange') to get the element to change the source of. No such element exists and even if it did, that would mean that clicking on any of the snowflakes would just change the source of that one image. You need to reference the snowflake that you clicked on. An easy way to do this is by passing this as an argument to the function in the onclick attribute:
HTML:
<div class="snowflake"><img src="https://vignette.wikia.nocookie.net/dragonballfanon/images/7/70/Random.png/revision/latest?cb=20161221030547" onclick="changeImage(this)"></div>
JS:
function changeImage(img) {
img.src = 'https://i.pinimg.com/originals/6e/19/56/6e195649034f042d1dea5230234570a8.gif';
}
Finally, your JSFiddle is configured to delay execution of the JavaScript until after the DOM is ready. This means that the code will be wrapped in a callback function, and therefore the changeImage() function will no longer be in the global scope. This makes it inaccessible to the elements that want to call it in their handlers (the snowflakes). Because you are already listening for the DOMContentLoaded event on your own, you can just change the code to execute normally and it should work. Click on the dropdown that says "JavaScript + jQuery 3.2.1" above your JS code and change the load type to any "No wrap" option and it should work.
I would like to trigger an event when the window scroll velocity goes above a certain value. I found some code that will help measure the velocity but I can't work out why the if statement is not triggered when the speed goes above 150. Any help would be greatly appreciated.
const checkScrollSpeed = (function(settings){
settings = settings || {};
let lastPos, newPos, timer, delta,
delay = settings.delay || 50;
function clear() {
lastPos = null;
delta = 0;
}
clear();
return function(){
newPos = window.scrollY;
if ( lastPos != null ){ // && newPos < maxScroll
delta = newPos - lastPos;
}
lastPos = newPos;
clearTimeout(timer);
timer = setTimeout(clear, delay);
return delta;
};
})();
const container = document.querySelector('#container');
window.addEventListener('scroll', function() {
console.log(checkScrollSpeed());
if (checkScrollSpeed() > 150) {
console.log('150+')
container.classList.add('red');
}
});
#container {
width: 75%;
height: 170vh;
background-color: yellow;
}
#container.red {
background-color: red !important;
}
<div id="container"></div>
You are calling checkScrollSpeed in succession and when it's called the second time delta is 0. Either remove the console.log or assign delta to some variable and use that for logging and the condition.
I think it's because you have a little delay between the first time you call checkScrollSpeed() in your console.log and then in your if statement. You can try to call it only once and save the value for your console.log and if statement. It works for me with this solution:
const checkScrollSpeed = (function(settings) {
settings = settings || {};
let lastPos, newPos, timer, delta,
delay = settings.delay || 50;
function clear() {
lastPos = null;
delta = 0;
}
clear();
return function() {
newPos = window.scrollY;
if (lastPos != null) { // && newPos < maxScroll
delta = newPos - lastPos;
}
lastPos = newPos;
clearTimeout(timer);
timer = setTimeout(clear, delay);
return delta;
};
})();
const container = document.querySelector('#container');
window.addEventListener('scroll', function() {
var speed = checkScrollSpeed();
console.log(speed);
if (speed > 150) {
console.log('150+');
container.classList.add('red');
}
});
#container {
width: 75%;
height: 170vh;
background-color: yellow;
}
#container.red {
background-color: red !important;
}
<div id="container"></div>
GChat keeps the textarea scrolled to the end when new text appears, however if the user scrolls away from the end, it waits until you've scrolled back down to continue this behavior.
Using just HTML, Javascript and JQuery, how could one mimic this behavior?
Every time you add data, execute something like:
this.scrollTop = this.scrollHeight;
This is just standard Javascript that forces you to scroll to the bottom. To only force someone to stay scrolled to the bottom when they're already at the bottom, do something like this:
var elem = document.getElementById('myElementName');
var atBottom = (elem.scrollTop >= (elem.scrollHeight - elem.clientHeight));
// add your text updates here
if(atBottom) elem.scrollTop = elem.scrollHeight;
Example at http://jsfiddle.net/xjmha/4/
(Ignore the other versions of the fiddle... I was failing with jQuery.)
try something like this :)
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style type="text/css">
textarea {
height: 80px;
width: 450px;
}
</style>
<script type="text/javascript">
var foo = function(){
var t = document.getElementById('foo');
if(t['data-scrollinglocked'])return;
var h = t.scrollHeight;
t.scrollTop = h;
}
var moo = function(){
var t = document.getElementById('foo');
t.innerHTML = t.innerHTML + new Date()+"\n";
}
var init = function(){
// global scope ;)
mooInterval = setInterval("moo()",1000);
fooInterval = setInterval("foo()",500);
var t = document.getElementById('foo');
t['data-scrollinglocked'] = 0;
t.onmouseout = function(){
t['data-scrollinglocked'] = 0;
};
t.onmouseover = function(){
t['data-scrollinglocked'] = 1;
};
t.onclick = function(){
t['data-scrollinglocked'] = 1;
};
t.onblur = function(){
t['data-scrollinglocked'] = 1;
};
t.onfocus = function(){
t['data-scrollinglocked'] = 1;
};
t.onblur= function(){
t['data-scrollinglocked'] = 0;
};
}
</script>
</head>
<body>
<div class="foo"></div>
<textarea id="foo"></textarea>
<script>init();</script>
</body>
</html>
I'm hopeless at Javascript. This is what I have:
<script type="text/javascript">
function beginrefresh(){
//set the id of the target object
var marquee = document.getElementById("marquee_text");
if(marquee.scrollLeft >= marquee.scrollWidth - parseInt(marquee.style.width)) {
marquee.scrollLeft = 0;
}
marquee.scrollLeft += 1;
// set the delay (ms), bigger delay, slower movement
setTimeout("beginrefresh()", 10);
}
</script>
It scrolls to the left but I need it to repeat relatively seamlessly. At the moment it just jumps back to the beginning. It might not be possible the way I've done it, if not, anyone have a better method?
Here is a jQuery plugin with a lot of features:
http://jscroller2.markusbordihn.de/example/image-scroller-windiv/
And this one is "silky smooth"
http://remysharp.com/2008/09/10/the-silky-smooth-marquee/
Simple javascript solution:
window.addEventListener('load', function () {
function go() {
i = i < width ? i + step : 1;
m.style.marginLeft = -i + 'px';
}
var i = 0,
step = 3,
space = ' ';
var m = document.getElementById('marquee');
var t = m.innerHTML; //text
m.innerHTML = t + space;
m.style.position = 'absolute'; // http://stackoverflow.com/questions/2057682/determine-pixel-length-of-string-in-javascript-jquery/2057789#2057789
var width = (m.clientWidth + 1);
m.style.position = '';
m.innerHTML = t + space + t + space + t + space + t + space + t + space + t + space + t + space;
m.addEventListener('mouseenter', function () {
step = 0;
}, true);
m.addEventListener('mouseleave', function () {
step = 3;
}, true);
var x = setInterval(go, 50);
}, true);
#marquee {
background:#eee;
overflow:hidden;
white-space: nowrap;
}
<div id="marquee">
1 Hello world! 2 Hello world! 3 Hello world!
</div>
JSFiddle
I recently implemented a marquee in HTML using Cycle 2 Jquery plugin :
http://jquery.malsup.com/cycle2/demo/non-image.php
<div class="cycle-slideshow" data-cycle-fx="scrollHorz" data-cycle-speed="9000" data-cycle-timeout="1" data-cycle-easing="linear" data-cycle-pause-on-hover="true" data-cycle-slides="> div" >
<div> Text 1 </div>
<div> Text 2 </div>
</div>
HTML5 does not support the tag, however a lot of browsers will still display the text "properly" but your code will not validate. If this isn't an issue for you, that may be an option.
CSS3 has the ability, supposedly, to have marquee text, however because anyone that knows how to do it believes it's a "bad idea" for CSS, there is very limited information that I have found online. Even the W3 documents do not go into enough detail for the hobbyist or self-teaching person to implement it.
PHP and Perl can duplicate the effect as well. The script needed for this would be insanely complicated and take up much more resources than any other options. There is also the possibility that the script would run too quickly on some browsers, causing the effect to be completely negated.
So back to JavaScript - Your code (OP) seems to be about the cleanest, simplest, most effective I've found. I will be trying this. For the seamless thing, I will be looking into a way to limit the white space between end and beginning, possibly with doing a while loop (or similar) and actually run two of the script, letting one rest while the other is processing.
There may also be a way with a single function change to eliminate the white space. I'm new to JS, so don't know off the top of my head. - I know this isn't a full-on answer, but sometimes ideas can cause results, if only for someone else.
This script used to replace the marquee tag
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('.scrollingtext').bind('marquee', function() {
var ob = $(this);
var tw = ob.width();
var ww = ob.parent().width();
ob.css({ right: -tw });
ob.animate({ right: ww }, 20000, 'linear', function() {
ob.trigger('marquee');
});
}).trigger('marquee');
});
</script>
<div class="scroll">
<div class="scrollingtext"> Flash message without marquee tag using javascript! </div>
</div>
Working with #Stano code and some jQuery I have created a script that will replace the old marquee tag with standard div. The code will also parse the marquee attributes like direction, scrolldelay and scrollamount.
Here is the code:
jQuery(function ($) {
if ($('marquee').length == 0) {
return;
}
$('marquee').each(function () {
let direction = $(this).attr('direction');
let scrollamount = $(this).attr('scrollamount');
let scrolldelay = $(this).attr('scrolldelay');
let newMarquee = $('<div class="new-marquee"></div>');
$(newMarquee).html($(this).html());
$(newMarquee).attr('direction',direction);
$(newMarquee).attr('scrollamount',scrollamount);
$(newMarquee).attr('scrolldelay',scrolldelay);
$(newMarquee).css('white-space', 'nowrap');
let wrapper = $('<div style="overflow:hidden"></div>').append(newMarquee);
$(this).replaceWith(wrapper);
});
function start_marquee() {
let marqueeElements = document.getElementsByClassName('new-marquee');
let marqueLen = marqueeElements.length
for (let k = 0; k < marqueLen; k++) {
let space = ' ';
let marqueeEl = marqueeElements[k];
let direction = marqueeEl.getAttribute('direction');
let scrolldelay = marqueeEl.getAttribute('scrolldelay') * 100;
let scrollamount = marqueeEl.getAttribute('scrollamount');
let marqueeText = marqueeEl.innerHTML;
marqueeEl.innerHTML = marqueeText + space;
marqueeEl.style.position = 'absolute';
let width = (marqueeEl.clientWidth + 1);
let i = (direction == 'rigth') ? width : 0;
let step = (scrollamount !== undefined) ? parseInt(scrollamount) : 3;
marqueeEl.style.position = '';
marqueeEl.innerHTML = marqueeText + space + marqueeText + space;
let x = setInterval( function () {
if ( direction.toLowerCase() == 'left') {
i = i < width ? i + step : 1;
marqueeEl.style.marginLeft = -i + 'px';
} else {
i = i > -width ? i - step : width;
marqueeEl.style.marginLeft = -i + 'px';
}
}, scrolldelay);
}
}
start_marquee ();
});
And here is a working codepen
I was recently working on a site that needed a marquee and had initially used the dynamic marquee, which worked well but I couldn't have the text begin off the screen. Took a look around but couldn't find anything quite as simple as I wanted so I made my own:
<div id="marquee">
<script type="text/javascript">
let marquee = $('#marquee p');
const appendToMarquee = (content) => {
marquee.append(content);
}
const fillMarquee = (itemsToAppend, content) => {
for (let i = 0; i < itemsToAppend; i++) {
appendToMarquee(content);
}
}
const animateMarquee = (itemsToAppend, content, width) => {
fillMarquee(itemsToAppend, content);
marquee.animate({left: `-=${width}`,}, width*10, 'linear', function() {
animateMarquee(itemsToAppend, content, width);
})
}
const initMarquee = () => {
let width = $(window).width(),
marqueeContent = "YOUR TEXT",
itemsToAppend = width / marqueeContent.split("").length / 2;
animateMarquee(itemsToAppend, marqueeContent, width);
}
initMarquee();
</script>
And the CSS:
#marquee {
overflow: hidden;
margin: 0;
padding: 0.5em 0;
bottom: 0;
left: 0;
right: 0;
background-color: #000;
color: #fff;
}
#marquee p {
white-space: nowrap;
margin: 0;
overflow: visible;
position: relative;
left: 0;
}