There is an animation of the flight of leaves in pure js. The problem is that it needs to be optimized for maximum performance, because there will be more animations of this kind on the page. Besides optimizing the original SVG image and reducing the number of leaflets, what tips can you give to improve the performance of your code?
var LeafScene = function(el) {
this.viewport = el;
this.world = document.createElement('div');
this.leaves = [];
this.options = {
numLeaves: 6,
wind: {
magnitude: 0,
maxSpeed: 12,
duration: 300,
start: 0,
speed: 10
},
};
this.width = this.viewport.offsetWidth;
this.height = this.viewport.offsetHeight;
this.timer = 0;
this._resetLeaf = function(leaf) {
leaf.x = this.width * 2 - Math.random()*this.width*1.75;
leaf.y = -10;
leaf.z = Math.random()*200;
if (leaf.x > this.width) {
leaf.x = this.width + 10;
leaf.y = Math.random()*this.height/2;
}
if (this.timer == 0) {
leaf.y = Math.random()*this.height;
}
leaf.rotation.speed = Math.random()*10;
var randomAxis = Math.random();
if (randomAxis > 0.5) {
leaf.rotation.axis = 'X';
} else if (randomAxis > 0.25) {
leaf.rotation.axis = 'Y';
leaf.rotation.x = Math.random()*180 + 90;
} else {
leaf.rotation.axis = 'Z';
leaf.rotation.x = Math.random()*360 - 180;
leaf.rotation.speed = Math.random()*3;
}
leaf.xSpeedVariation = Math.random() * 0.8 - 0.4;
leaf.ySpeed = Math.random() + 1.5;
return leaf;
}
this._updateLeaf = function(leaf) {
var leafWindSpeed = this.options.wind.speed(this.timer - this.options.wind.start, leaf.y);
var xSpeed = leafWindSpeed + leaf.xSpeedVariation;
leaf.x -= xSpeed;
leaf.y += leaf.ySpeed;
leaf.rotation.value += leaf.rotation.speed;
var t = 'translateX( ' + leaf.x + 'px ) translateY( ' + leaf.y + 'px ) translateZ( ' + leaf.z + 'px ) rotate' + leaf.rotation.axis + '( ' + leaf.rotation.value + 'deg )';
if (leaf.rotation.axis !== 'X') {
t += ' rotateX(' + leaf.rotation.x + 'deg)';
}
leaf.el.style.webkitTransform = t;
leaf.el.style.MozTransform = t;
leaf.el.style.oTransform = t;
leaf.el.style.transform = t;
if (leaf.x < -10 || leaf.y > this.height + 10) {
this._resetLeaf(leaf);
}
}
this._updateWind = function() {
if (this.timer === 0 || this.timer > (this.options.wind.start + this.options.wind.duration)) {
this.options.wind.magnitude = Math.random() * this.options.wind.maxSpeed;
this.options.wind.duration = this.options.wind.magnitude * 50 + (Math.random() * 20 - 10);
this.options.wind.start = this.timer;
var screenHeight = this.height;
this.options.wind.speed = function(t, y) {
var a = this.magnitude/2 * (screenHeight - 2*y/3)/screenHeight;
return a * Math.sin(2*Math.PI/this.duration * t + (3 * Math.PI/2)) + a;
}
}
}
}
LeafScene.prototype.init = function() {
for (var i = 0; i < this.options.numLeaves; i++) {
var leaf = {
el: document.createElement('div'),
x: 0,
y: 0,
z: 0,
rotation: {
axis: 'X',
value: 0,
speed: 0,
x: 0
},
xSpeedVariation: 0,
ySpeed: 0,
path: {
type: 1,
start: 0,
},
image: 1
};
this._resetLeaf(leaf);
this.leaves.push(leaf);
this.world.appendChild(leaf.el);
}
this.world.className = 'leaf-scene';
this.viewport.appendChild(this.world);
this.world.style.webkitPerspective = "400px";
this.world.style.MozPerspective = "400px";
this.world.style.oPerspective = "400px";
this.world.style.perspective = "400px";
var self = this;
window.onresize = function(event) {
self.width = self.viewport.offsetWidth;
self.height = self.viewport.offsetHeight;
};
}
LeafScene.prototype.render = function() {
this._updateWind();
for (var i = 0; i < this.leaves.length; i++) {
this._updateLeaf(this.leaves[i]);
}
this.timer++;
requestAnimationFrame(this.render.bind(this));
}
var leafContainer = document.querySelector('.falling-leaves'),
leaves = new LeafScene(leafContainer);
leaves.init();
leaves.render();
body, html {
height: 100%;
}
.falling-leaves {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 100%;
max-width: 880px;
max-height: 880px;
transform: translate(-50%, 0);
border: 20px solid #fff;
border-radius: 50px;
background-size: cover;
overflow: hidden;
}
.leaf-scene {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
transform-style: preserve-3d;
}
.leaf-scene div {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background: url(https://www.flaticon.com/svg/static/icons/svg/892/892881.svg) no-repeat;
background-size: 100%;
transform-style: preserve-3d;
-webkit-backface-visibility: visible;
backface-visibility: visible;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<div class="falling-leaves"></div>
Unless you're using HTML Canvas, vanilla JS solutions are pretty heavy compared to CSS/JS hybrid because of the browser call stack.
It looks like this:
JS > Style > Layout > Paint > Composite
By minimizing the amount of calculations the browser has to do in JS and grouping reads/writes to the DOM you'll see a significant performance increase. The workload can be recorded with Chrome Dev tools under 'Performance' tab. And you'll be able to see every step the browser is taking to display the content. The less steps, the better performance .. simple as that.
You're writing to the DOM every single transform which is heavy even with 3d acceleration.
I usually make use of CSS variables and transitions for dynamic animation that I update in steps.
What you did is great otherwise. Try rendering on a HTML Canvas and your performance problems will vanish. Here's a start:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
But if you want or cant do canvas adapt to utilize CSS to not drop further than the Paint browser call for majority of frames.
Related
I have a heart movement on my page starting from the bottom of the page. Each randomly generates the size and speed of movement.
How can I make them, instead of appearing at the bottom of the page, appear when you click on the specified place, and move not evenly, but more chaotically and disappear before reaching the end?
var love = setInterval(function() {
var r_num = Math.floor(Math.random() * 40) + 1;
var r_size = Math.floor(Math.random() * 30) + 10;
var r_left = Math.floor(Math.random() * 100) + 1;
var r_time = Math.floor(Math.random() * 5) + 5;
$('.bg_heart').append("<div class='heart' style='width:" + r_size + "px;height:" + r_size + "px;left:" + r_left + "%;background:#ff94a7;-webkit-animation:love " + r_time + "s ease;-moz-animation:love " + r_time + "s ease;-ms-animation:love " + r_time + "s ease;animation:love " + r_time + "s ease'></div>");
$('.bg_heart').append("<div class='heart' style='width:" + (r_size - 10) + "px;height:" + (r_size - 10) + "px;left:" + (r_left + r_num) + "%;background:#ff94a7;-webkit-animation:love " + (r_time + 5) + "s ease;-moz-animation:love " + (r_time + 5) + "s ease;-ms-animation:love " + (r_time + 5) + "s ease;animation:love " + (r_time + 5) + "s ease'></div>");
$('.heart').each(function() {
var top = $(this).css("top").replace(/[^-\d\.]/g, '');
var width = $(this).css("width").replace(/[^-\d\.]/g, '');
if (top <= -100 || width >= 150) {
$(this).detach();
}
});
}, 500);
html,body{
height:100%
}
.bg_heart {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden
}
.heart {
position: absolute;
top: -50%;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-m-transform: rotate(-45deg);
transform: rotate(-45deg)
}
.heart:before {
position: absolute;
top: -50%;
left: 0;
display: block;
content: "";
width: 100%;
height: 100%;
background: inherit;
border-radius: 100%;
}
.heart:after {
position: absolute;
top: 0;
right: -50%;
display: block;
content: "";
width: 100%;
height: 100%;
background: inherit;
border-radius: 100%;
}
#-webkit-keyframes love {
0%{top:110%}
}
#-moz-keyframes love {
0%{top:110%}
}
#-ms-keyframes love {
0%{top:110%}
}
#keyframes love {
0%{top:110%}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="header-plugin"></div>
<div class="bg_heart"></div>
To fly more chaotically use setInterval. You can also change the speed to whatever you need.
var brd = document.createElement("DIV");
document.body.insertBefore(brd, document.getElementById("board"));
const duration = 3000;
const speed = 0.5;
const cursorXOffset = 0;
const cursorYOffset = -5;
var hearts = [];
function generateHeart(x, y, xBound, xStart, scale)
{
var heart = document.createElement("DIV");
heart.setAttribute('class', 'heart');
brd.appendChild(heart);
heart.time = duration;
heart.x = x;
heart.y = y;
heart.bound = xBound;
heart.direction = xStart;
heart.style.left = heart.x + "px";
heart.style.top = heart.y + "px";
heart.scale = scale;
heart.style.transform = "scale(" + scale + "," + scale + ")";
if(hearts == null)
hearts = [];
hearts.push(heart);
return heart;
}
var down = false;
var event = null;
document.onmousedown = function(e) {
down = true;
event = e;
}
document.onmouseup = function(e) {
down = false;
}
document.onmousemove = function(e) {
event = e;
}
document.ontouchstart = function(e) {
down = true;
event = e.touches[0];
}
document.ontouchend = function(e) {
down = false;
}
document.ontouchmove = function(e) {
event = e.touches[0];
}
var before = Date.now();
var id = setInterval(frame, 5);
var gr = setInterval(check, 100);
function frame()
{
var current = Date.now();
var deltaTime = current - before;
before = current;
for(i in hearts)
{
var heart = hearts[i];
heart.time -= deltaTime;
if(heart.time > 0)
{
heart.y -= speed;
heart.style.top = heart.y + "px";
heart.style.left = heart.x + heart.direction * heart.bound * Math.sin(heart.y * heart.scale / 30) / heart.y * 100 + "px";
}
else
{
heart.parentNode.removeChild(heart);
hearts.splice(i, 1);
}
}
}
function check()
{
if(down)
{
var start = 1 - Math.round(Math.random()) * 2;
var scale = Math.random() * Math.random() * 0.8 + 0.2;
var bound = 30 + Math.random() * 20;
generateHeart(event.pageX - brd.offsetLeft + cursorXOffset, event.pageY - brd.offsetTop + cursorYOffset, bound, start, scale);
}
}
html,body{
height:100%
}
#keyframes heartfade {
0% {
opacity : 1;
}
50% {
opacity : 0;
}
}
.heart {
z-index : 999;
animation : heartfade 6s linear;
position : absolute;
}
.heart:before,
.heart:after {
content : "";
background-color : #ff94a7;
position : absolute;
height : 30px;
width : 45px;
border-radius : 15px 0px 0px 15px;
}
.heart:before {
transform : rotate(45deg);
}
.heart:after {
left : 10.5px;
transform : rotate(135deg);
}
Good day Guys,
I am trying to use a spinner that shows on the entire page when i click on Submit button. The below are the codes snippets.
This is the JS code
<script type="text/javascript"
src="#Url.Content("~/Scripts/spin.js")"></script>
<script type="text/javascript">
$(function () {
$("#searchbtn").click(function () {
$("#loading").fadeIn();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false // Whether to use hardware acceleration
};
var target = document.getElementById('loading');
//var spinner = new Spinner(opts).spin(target);
var spinner = new Spin.Spinner(opts).spin(target);
});
});
This is the CSS below
#loading {
display: none;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.8);
z-index: 1000;
}
#loadingcontent {
display: table;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#loadingspinner {
display: table-cell;
vertical-align: middle;
width: 100%;
text-align: center;
font-size: larger;
padding-top: 80px;
}
Below is the DIV that holds the searching.
<div id="loading">
<div id="loadingcontent">
<p id="loadingspinner">
Searching things...
</p>
</div>
</div>
<div class="col-md-12">
<p>
#using (Html.BeginForm("AllLoanProcessed", "Transactions", new { area = "Transactions" }, FormMethod.Get))
{
<b>Search By:</b>
#Html.RadioButton("searchBy", "Account_Number", true) <text>Account Number</text>
#Html.RadioButton("searchBy", "Surname") <text> Surname </text> <br />
#Html.TextBox("search", null, new { placeholder = "Search Value", #class = "form-control" })
<br />
<input type="submit" value="Search" id="searchbtn" class="btn btn-primary btn-block" />
}
</p>
</div>
The issue is that, when i click on the search button, The spin does not load.
Am I missing something? OR any one has any other spinner method that works that will cover the whole page when running.
EDIT:
The below is the spin.js file content.
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function (t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var defaults = {
lines: 12,
length: 7,
width: 5,
radius: 10,
scale: 1.0,
corners: 1,
color: '#000',
fadeColor: 'transparent',
animation: 'spinner-line-fade-default',
rotate: 0,
direction: 1,
speed: 1,
zIndex: 2e9,
className: 'spinner',
top: '50%',
left: '50%',
shadow: '0 0 1px transparent',
position: 'absolute',
};
var Spinner = /** #class */ (function () {
function Spinner(opts) {
if (opts === void 0) { opts = {}; }
this.opts = __assign(__assign({}, defaults), opts);
}
/**
* Adds the spinner to the given target element. If this instance is already
* spinning, it is automatically removed from its previous target by calling
* stop() internally.
*/
Spinner.prototype.spin = function (target) {
this.stop();
this.el = document.createElement('div');
this.el.className = this.opts.className;
this.el.setAttribute('role', 'progressbar');
css(this.el, {
position: this.opts.position,
width: 0,
zIndex: this.opts.zIndex,
left: this.opts.left,
top: this.opts.top,
transform: "scale(" + this.opts.scale + ")",
});
if (target) {
target.insertBefore(this.el, target.firstChild || null);
}
drawLines(this.el, this.opts);
return this;
};
/**
* Stops and removes the Spinner.
* Stopped spinners may be reused by calling spin() again.
*/
Spinner.prototype.stop = function () {
if (this.el) {
if (typeof requestAnimationFrame !== 'undefined') {
cancelAnimationFrame(this.animateId);
}
else {
clearTimeout(this.animateId);
}
if (this.el.parentNode) {
this.el.parentNode.removeChild(this.el);
}
this.el = undefined;
}
return this;
};
return Spinner;
}());
export { Spinner };
/**
* Sets multiple style properties at once.
*/
function css(el, props) {
for (var prop in props) {
el.style[prop] = props[prop];
}
return el;
}
/**
* Returns the line color from the given string or array.
*/
function getColor(color, idx) {
return typeof color == 'string' ? color : color[idx % color.length];
}
/**
* Internal method that draws the individual lines.
*/
function drawLines(el, opts) {
var borderRadius = (Math.round(opts.corners * opts.width * 500) / 1000) +
'px';
var shadow = 'none';
if (opts.shadow === true) {
shadow = '0 2px 4px #000'; // default shadow
}
else if (typeof opts.shadow === 'string') {
shadow = opts.shadow;
}
var shadows = parseBoxShadow(shadow);
for (var i = 0; i < opts.lines; i++) {
var degrees = ~~(360 / opts.lines * i + opts.rotate);
var backgroundLine = css(document.createElement('div'), {
position: 'absolute',
top: -opts.width / 2 + "px",
width: (opts.length + opts.width) + 'px',
height: opts.width + 'px',
background: getColor(opts.fadeColor, i),
borderRadius: borderRadius,
transformOrigin: 'left',
transform: "rotate(" + degrees + "deg) translateX(" + opts.radius +
"px)",
});
var delay = i * opts.direction / opts.lines / opts.speed;
delay -= 1 / opts.speed; // so initial animation state will include trail
var line = css(document.createElement('div'), {
width: '100%',
height: '100%',
background: getColor(opts.color, i),
borderRadius: borderRadius,
boxShadow: normalizeShadow(shadows, degrees),
animation: 1 / opts.speed + "s linear " + delay + "s infinite " +
opts.animation,
});
backgroundLine.appendChild(line);
el.appendChild(backgroundLine);
}
}
function parseBoxShadow(boxShadow) {
var regex = /^\s*([a-zA-Z]+\s+)?(-?\d+(\.\d+)?)([a-zA-Z]*)\s+(-?\d+(\.\d+)?)
([a-zA-Z]*)(.*)$/;
var shadows = [];
for (var _i = 0, _a = boxShadow.split(','); _i < _a.length; _i++) {
var shadow = _a[_i];
var matches = shadow.match(regex);
if (matches === null) {
continue; // invalid syntax
}
var x = +matches[2];
var y = +matches[5];
var xUnits = matches[4];
var yUnits = matches[7];
if (x === 0 && !xUnits) {
xUnits = yUnits;
}
if (y === 0 && !yUnits) {
yUnits = xUnits;
}
if (xUnits !== yUnits) {
continue; // units must match to use as coordinates
}
shadows.push({
prefix: matches[1] || '',
x: x,
y: y,
xUnits: xUnits,
yUnits: yUnits,
end: matches[8],
});
}
return shadows;
}
/**
* Modify box-shadow x/y offsets to counteract rotation
*/
function normalizeShadow(shadows, degrees) {
var normalized = [];
for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {
var shadow = shadows_1[_i];
var xy = convertOffset(shadow.x, shadow.y, degrees);
normalized.push(shadow.prefix + xy[0] + shadow.xUnits + ' ' + xy[1] +
shadow.yUnits + shadow.end);
}
return normalized.join(', ');
}
function convertOffset(x, y, degrees) {
var radians = degrees * Math.PI / 180;
var sin = Math.sin(radians);
var cos = Math.cos(radians);
return [
Math.round((x * cos + y * sin) * 1000) / 1000,
Math.round((-x * sin + y * cos) * 1000) / 1000,
];
}
why my checkCollision function is not working in foreach loop ? I want to check whether obs (obstacle) is hits/overlaps on collector (gray object). I am checking every 1 millisecond using setInterval checkCollision function. Basically I am trying to build a simple car game. please help me and thank you in advance
let body = document.body[0];
let container = document.querySelector(".container");
let allObstacles = [];
let colors = ["green", "green", "red"];
let collector = document.getElementById("collector");
class Obstacle {
constructor(yPos) {
this.yPos = -50;
}
randomnum() {
let randX = Math.floor(Math.random() * (container.clientWidth - 50));
return randX;
}
createObstacle() {
let obstacle = document.createElement("div");
obstacle.classList.add("obstacle");
let bgColor = colors[Math.floor(Math.random() * colors.length)];
obstacle.style.width = "50px";
obstacle.style.height = "50px";
obstacle.style.position = "absolute";
obstacle.style.left = this.randomnum() + "px";
obstacle.style.top = this.yPos + "px";
obstacle.style.backgroundColor = bgColor;
obstacle.dataset.behave = bgColor;
container.appendChild(obstacle);
return obstacle;
}
element = this.createObstacle();
updatePosition() {
this.yPos += 2;
this.element.style.top = this.yPos + "px";
}
kill() {
this.element.remove();
}
}
let dropObs = setInterval(function() {
allObstacles.forEach(function(obs) {
obs.updatePosition();
});
allObstacles.forEach(function(obs) {
// why checkCollision function is not working?
if (checkCollision(obs, collector)) {
console.log("hit");
}
if (obs.yPos > container.clientHeight) {
obs.kill();
}
});
}, 10);
let generateObs = setInterval(function() {
let obs = new Obstacle();
allObstacles.push(obs);
}, 2000);
function checkCollision(obj1, obj2) {
var obj1Y = obj1.offsetTop;
var obj2Y = obj2.offsetTop;
var obj1X = obj1.offsetLeft;
var obj2X = obj2.offsetLeft;
if (
obj2Y + 100 >= obj1Y &&
obj2Y <= obj1Y + 100 &&
obj2X + 100 >= obj1X &&
obj2X <= obj1X + 100
) {
return 1;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.container {
position: relative;
width: 100%;
height: 100%;
}
#collector {
width: 50px;
height: 100px;
background: gray;
position: absolute;
top: calc(100vh - 100px);
left: 50%;
margin-left: -25px;
}
<div class="container">
<div id="collector"></div>
</div>
The first thing you should not use setInterval for this type of animation. Use requestAnimationFrame
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
obj1X,obj1Y comming undefined.
Little premise: I didn't want to make this question, because I thought it was a too personal and generic problem; but after 2 days without any improvement, I couldn't resist anymore.
So basically, my project is an aquarium with multiple fishes inside.
It all works fine, the only problem is that, in short words: the first fish image remains inside the div(it even stops too soon), the second one arrives a bit farther, the third even farther, and so on.
The opposite thing happens with the top margin: going forward, the last fish is always farther from the margin, and I can't find out the reason.
My scope is to keep all the fishes inside the "acquario" div (which has the black borders).
P.S. With sx and dx margins, they have no problem.
var BORDER_LEFT_RIGHT = 7;
var BORDER_TOP_DOWN = 28;
var fishes = new Array();
var nextId = 0;
var heightMax;
var widthMax;
var n; //initial direction, see createFish()
init();
/* light blue fish (dory, to clarify)*/
createFish("https://s18.postimg.org/n8sqmtjkp/pesce1_sx.png", "https://s30.postimg.org/6w8xyqwep/pesce1_dx.png");
/* white and yellow fish */
createFish("https://s28.postimg.org/6aalv0pst/pesce2_sx.png", "https://s29.postimg.org/dxbi0vypz/pesce2_dx.png");
/* dark blue fish */
createFish("https://s24.postimg.org/sbgt8zn6t/pesce3_sx.png", "https://s29.postimg.org/v65opob7r/pesce3_dx.png");
/* white-blue-yellow fish */
createFish("https://s30.postimg.org/62lb9bfwx/pesce4_sx.png", "https://s28.postimg.org/kt5m4ea65/pesce4_dx.png");
/* orange fish */
createFish("https://s18.postimg.org/q5sq0saex/pesce5_sx.png", "https://s18.postimg.org/uqnwe2vex/pesce5_dx.png");
showFishes();
function init() {
heightMax = document.getElementById("acquario").clientHeight - BORDER_TOP_DOWN;
widthMax = document.getElementById("acquario").clientWidth - BORDER_LEFT_RIGHT;
n = 1;
}
function createFish(src1, src2) {
imgFishSX = new Image();
imgFishDX = new Image();
imgFishSX.src = src1;
imgFishDX.src = src2;
n *= -1;
var fish = {
id: nextId,
/* default x position: random number between 1 and widthMax */
x: Math.floor((Math.random() * widthMax - imgFishSX.width) + 1),
/* default y position: random number between 1 and heightMax */
y: Math.floor((Math.random() * heightMax - imgFishSX.height) + 1),
xIncrease: n * getIncrease(),
yIncrease: n * getIncrease(),
imageSX: imgFishSX,
imageDX: imgFishDX
};
addFishToArray((fish));
nextId++;
}
function addFishToArray(fish) {
fishes.push(fish);
}
function showFishes() {
var node = document.getElementById("acquario");
var stringToInner = "";
var src;
/* first, we make the string with all the img filled in */
for (var i = 0; i < fishes.length; i++) {
/* we have to check if the default increase direction was <-- or --> */
fishes[i].xIncrease > 0 ? src = fishes[i].imageSX.src : src = fishes[i].imageDX.src;
/* z-index --> overlap priority */
stringToInner += "<img src =\"" + src +
"\" id=\"" + fishes[i].id + "\" style= \"margin-left: " +
fishes[i].x + "px;margin-top: " + fishes[i].y + "px;z-index: " +
fishes[i].id + ";position: absolute;\">";
stringToInner += "<br>";
}
/* then, we insert it */
node.innerHTML = stringToInner;
/* let's raise hell! */
moveFishes();
}
function getIncrease() {
return Math.floor((Math.random() * 5) + 1);
}
function moveFishes() {
/* scroll the array: we need to check each fish one by one */
for (var i = 0; i < fishes.length; i++) {
moveFish(fishes[i]);
}
/* infinite loop */
setTimeout(function() {
moveFishes()
}, 50);
}
function moveFish(fish) {
/* with this node, I'll apply changes to my html document */
node = document.getElementById(fish.id);
/* we are inside, just move */
if (fish.x > 0 && fish.x < widthMax - node.width && fish.y > 0 && fish.y < heightMax - node.height) {
node.style.marginLeft = fish.x + "px";
node.style.marginTop = fish.y + "px";
fish.x += fish.xIncrease;
fish.y += fish.yIncrease;
/* too --> , we need to get <-- */
} else if (fish.x >= widthMax - node.width) {
node.src = fish.imageDX.src;
fish.xIncrease = -getIncrease();
fish.x += fish.xIncrease;
/* too <-- , we need to get --> */
} else if (fish.x <= 0) {
node.src = fish.imageSX.src;
fish.xIncrease = 5;
fish.x += getIncrease();
/* too up, we need to get down */
} else if (fish.y >= heightMax - node.height) {
fish.yIncrease = -getIncrease();
fish.y += fish.yIncrease;
/* too down, we need to get up */
} else if (fish.y <= 0) {
fish.yIncrease = getIncrease();
fish.y += fish.yIncrease;
}
}
* {
box-sizing: border-box;
}
.row::after {
content: "";
clear: both;
display: block;
}
html {
background: url("https://s24.postimg.org/rakxoa7sl/sfondo.jpg") no-repeat center center fixed;
-webkibact-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
html,
body {
height: 100%;
margin: 0;
}
#main {
margin: 0;
height: 100%;
}
#acquario {
border-bottom: 28px solid black;
border-top: 28px solid black;
border-right: 7px solid black;
border-left: 7px solid black;
height: 100%;
}
<body>
<div id="main">
<div id="acquario">
</div>
</div>
</body>
do you want the fishes to bound off the walls or to hide under the wall? and why do you use margin-left and margin-top instead of top and left properties? it makes the aquarium scrolling. Is it ok now?
var BORDER_LEFT_RIGHT = 7;
var BORDER_TOP_DOWN = 28;
var fishes = new Array();
var nextId = 0;
var heightMax;
var widthMax;
var n; //initial direction, see createFish()
init();
/* light blue fish (dory, to clarify)*/
createFish("https://s18.postimg.org/n8sqmtjkp/pesce1_sx.png", "https://s30.postimg.org/6w8xyqwep/pesce1_dx.png");
/* white and yellow fish */
createFish("https://s28.postimg.org/6aalv0pst/pesce2_sx.png", "https://s29.postimg.org/dxbi0vypz/pesce2_dx.png");
/* dark blue fish */
createFish("https://s24.postimg.org/sbgt8zn6t/pesce3_sx.png", "https://s29.postimg.org/v65opob7r/pesce3_dx.png");
/* white-blue-yellow fish */
createFish("https://s30.postimg.org/62lb9bfwx/pesce4_sx.png", "https://s28.postimg.org/kt5m4ea65/pesce4_dx.png");
/* orange fish */
createFish("https://s18.postimg.org/q5sq0saex/pesce5_sx.png", "https://s18.postimg.org/uqnwe2vex/pesce5_dx.png");
showFishes();
function init() {
heightMax = document.getElementById("acquario").clientHeight + BORDER_TOP_DOWN;
widthMax = document.getElementById("acquario").clientWidth + BORDER_LEFT_RIGHT;
n = 1;
}
function createFish(src1, src2) {
imgFishSX = new Image();
imgFishDX = new Image();
imgFishSX.src = src1;
imgFishDX.src = src2;
n *= -1;
var fish = {
id: nextId,
/* default x position: random number between 1 and widthMax */
x: Math.floor((Math.random() * (widthMax - BORDER_LEFT_RIGHT - imgFishSX.width)) + BORDER_LEFT_RIGHT),
/* default y position: random number between 1 and heightMax */
y: Math.floor((Math.random() * (heightMax - BORDER_TOP_DOWN - imgFishSX.height)) + BORDER_TOP_DOWN),
xIncrease: n * getIncrease(),
yIncrease: n * getIncrease(),
imageSX: imgFishSX,
imageDX: imgFishDX
};
addFishToArray((fish));
nextId++;
}
function addFishToArray(fish) {
fishes.push(fish);
}
function showFishes() {
var node = document.getElementById("acquario");
var stringToInner = "";
var src;
/* first, we make the string with all the img filled in */
for (var i = 0; i < fishes.length; i++) {
/* we have to check if the default increase direction was <-- or --> */
fishes[i].xIncrease > 0 ? src = fishes[i].imageSX.src : src = fishes[i].imageDX.src;
/* z-index --> overlap priority */
stringToInner += "<img src =\"" + src +
"\" id=\"" + fishes[i].id + "\" style= \"left: " +
fishes[i].x + "px;top: " + fishes[i].y + "px;z-index: " +
fishes[i].id + ";position: absolute;\">";
stringToInner += "<br>";
}
/* then, we insert it */
node.innerHTML = stringToInner;
/* let's raise hell! */
moveFishes();
}
function getIncrease() {
return Math.floor((Math.random() * 5) + 1);
}
function moveFishes() {
/* scroll the array: we need to check each fish one by one */
for (var i = 0; i < fishes.length; i++) {
moveFish(fishes[i]);
}
/* infinite loop */
setTimeout(function() {
moveFishes()
}, 50);
}
function moveFish(fish) {
/* with this node, I'll apply changes to my html document */
node = document.getElementById(fish.id);
/* we are inside, just move */
if (fish.x > BORDER_LEFT_RIGHT && fish.x < widthMax - node.width && fish.y > BORDER_TOP_DOWN && fish.y < heightMax - node.height) {
node.style.left = fish.x + "px";
node.style.top = fish.y + "px";
fish.x += fish.xIncrease;
fish.y += fish.yIncrease;
/* too --> , we need to get <-- */
} else if (fish.x >= widthMax - node.width) {
node.src = fish.imageDX.src;
fish.xIncrease = -getIncrease();
fish.x += fish.xIncrease;
/* too <-- , we need to get --> */
} else if (fish.x <= BORDER_LEFT_RIGHT) {
node.src = fish.imageSX.src;
fish.xIncrease = 5;
fish.x += getIncrease();
/* too up, we need to get down */
} else if (fish.y >= heightMax - node.height) {
fish.yIncrease = -getIncrease();
fish.y += fish.yIncrease;
/* too down, we need to get up */
} else if (fish.y <= BORDER_TOP_DOWN) {
fish.yIncrease = getIncrease();
fish.y += fish.yIncrease;
}
}
* {
box-sizing: border-box;
}
.row::after {
content: "";
clear: both;
display: block;
}
html {
background: url("https://s24.postimg.org/rakxoa7sl/sfondo.jpg") no-repeat center center fixed;
-webkibact-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
html,
body {
height: 100%;
margin: 0;
}
#main {
margin: 0;
height: 100%;
}
#acquario {
border-bottom: 28px solid black;
border-top: 28px solid black;
border-right: 7px solid black;
border-left: 7px solid black;
height: 100%;
}
<body>
<div id="main">
<div id="acquario">
</div>
</div>
</body>
I know Pawel has fixed your issue, but I did state I would provide a canvas version so here it is
jsFiddle : https://jsfiddle.net/CanvasCode/zh0b7zrj/1/
HTML :
<canvas id="myCanvas"></canvas>
CSS :
html,
body {
width: 100%;
height: 100%;
margin: 0px;
overflow: hidden;
}
Javascript :
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var backgroundImage = new Image();
canvas.width = document.body.clientWidth; //document.width is obsolete
canvas.height = document.body.clientHeight; //document.height is obsolete
// Fish
function FishObject(xSet, ySet, xSpeed, ySpeed, spriteUrlRight, spriteUrlLeft) {
this.XPos = xSet;
this.YPos = ySet;
this.XDefaultSpeed = xSpeed;
this.YDefaultSpeed = ySpeed;
this.xSpeed = this.XDefaultSpeed;
this.ySpeed = this.YDefaultSpeed;
this.RightSprite = new Image();
this.RightSprite.src = spriteUrlRight;
this.LeftSprite = new Image();
this.LeftSprite.src = spriteUrlLeft;
}
FishObject.prototype.Draw = function(ctx) {
if (this.xSpeed > 0) {
ctx.drawImage(this.RightSprite, this.XPos, this.YPos);
} else {
ctx.drawImage(this.LeftSprite, this.XPos, this.YPos);
}
}
FishObject.prototype.Update = function(ctx) {
this.XPos += this.xSpeed;
this.YPos += this.ySpeed;
if (this.XPos <= 0) {
this.xSpeed = this.XDefaultSpeed;
} else if ((this.XPos + this.RightSprite.width) >= canvas.width) {
this.xSpeed = -this.XDefaultSpeed;
}
if (this.YPos <= 0) {
this.ySpeed = this.YDefaultSpeed;
} else if ((this.YPos + this.RightSprite.height) >= canvas.height) {
this.ySpeed = -this.YDefaultSpeed;
}
}
backgroundImage.src = 'https://s24.postimg.org/rakxoa7sl/sfondo.jpg';
var Fishs = [];
Fishs.push(new FishObject(0, 0, 1, 1, "https://s18.postimg.org/n8sqmtjkp/pesce1_sx.png",
"https://s30.postimg.org/6w8xyqwep/pesce1_dx.png"));
Fishs.push(new FishObject(0, 0, 2, 1.2, "https://s28.postimg.org/6aalv0pst/pesce2_sx.png",
"https://s29.postimg.org/dxbi0vypz/pesce2_dx.png"));
Fishs.push(new FishObject(0, 0, 1.7, 2.8, "https://s24.postimg.org/sbgt8zn6t/pesce3_sx.png",
"https://s29.postimg.org/v65opob7r/pesce3_dx.png"));
Fishs.push(new FishObject(0, 0, 0.2, 0.5, "https://s30.postimg.org/62lb9bfwx/pesce4_sx.png",
"https://s28.postimg.org/kt5m4ea65/pesce4_dx.png"));
Fishs.push(new FishObject(0, 0, 0.7, 0.1, "https://s18.postimg.org/q5sq0saex/pesce5_sx.png",
"https://s18.postimg.org/uqnwe2vex/pesce5_dx.png"));
setInterval(function() {
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(backgroundImage, 0, 0);
for (var i = 0; i < Fishs.length; i++) {
var fishObject = Fishs[i];
fishObject.Draw(ctx);
fishObject.Update(ctx);
}
}, (1000 / 60)); // 60 FPS (frames per second)
ive been looking in about for this exact script for a while and i cant get it to work. Im looking to use a fade in effect from left to right word by word.
For example
<div class="box5">
<h1>Lorem ipsum dolor sit amet, ne mel vero impetus voluptatibus
</h1>
</div>
I want this to fade in then enough line to fade in word by word slightly later using a delay.
My current fade in works but it does it by the full container it looks like this
.reveal {
position: relative;
overflow: hidden;
}
/*initial - hidden*/
.reveal .reveal__cover {
position: absolute;
top: 0;
left: -250px;
height: 100%;
margin: 2px;
width: calc(100% + 250px);
}
.reveal .reveal__cover.reveal__uncovered {
position: absolute;
top: 0;
left: 100%;
height: 100%;
width: calc(100% + 250px);
margin: 2px;
transition: left 2500ms ease-out 0ms;
}
.reveal__cover-section {
height: 100%;
float: right;
/* NOTE: Background must match existing background */
/*background: #000;*/
background: #fff;
width: 2%;
}
.reveal__10 {
opacity: 0.1;
}
.reveal__20 {
opacity: 0.2;
}
.reveal__30 {
opacity: 0.3;
}
.reveal__40 {
opacity: 0.4;
}
.reveal__50 {
opacity: 0.5;
}
.reveal__60 {
opacity: 0.6;
}
.reveal__70 {
opacity: 0.7;
}
.reveal__80 {
opacity: 0.8;
}
.reveal__90 {
opacity: 0.9;
}
.reveal__100 {
opacity: 1;
width: 82%;
}
Then JS
function replaceAllInstances(source, search, replacement) {
var regex = new RegExp(search, "g");
var result = source.replace(regex, replacement);
return result;
}
$.fn.isOnScreen = function (x, y) {
if (x == null || typeof x == 'undefined')
x = 1;
if (y == null || typeof y == 'undefined')
y = 1;
var win = $(window);
var viewport = {
top: win.scrollTop(),
left: win.scrollLeft()
};
viewport.right = viewport.left + win.width();
viewport.bottom = viewport.top + win.height();
var height = this.outerHeight();
var width = this.outerWidth();
if (!width || !height) {
return false;
}
var bounds = this.offset();
bounds.right = bounds.left + width;
bounds.bottom = bounds.top + height;
var visible = (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
if (!visible) {
return false;
}
var deltas = {
top: Math.min(1, (bounds.bottom - viewport.top) / height),
bottom: Math.min(1, (viewport.bottom - bounds.top) / height),
left: Math.min(1, (bounds.right - viewport.left) / width),
right: Math.min(1, (viewport.right - bounds.left) / width)
};
return (deltas.left * deltas.right) >= x && (deltas.top * deltas.bottom) >= y;
};
/*
* Init specified element so it can be gradually revealed.
*
* Limitations:
* Only works on backgrounds with a solid color.
*
* #param options = {
* id:'box3'
* ,background='#ffffff' //default
* ,delay='0' //default
* }
*
*/
$.fn.initReveal = function (options) {
console.log('-------------');
console.log('selector:' + this.selector);
var parent = $(this).parent();
//grab a copy of the contents, then remove it from DOM
var contents = $(this).clone();
$(this).empty();
var revealHtmlBlock = "<div class='reveal'> <div class='text reveal__inner reveal__inner-{class}'> </div> <div class='reveal__cover reveal__cover-{class}'> <div class='reveal__cover-section reveal__100'></div> <div class='reveal__cover-section reveal__90'></div> <div class='reveal__cover-section reveal__80'></div> <div class='reveal__cover-section reveal__70'></div> <div class='reveal__cover-section reveal__60'></div> <div class='reveal__cover-section reveal__50'></div> <div class='reveal__cover-section reveal__40'></div> <div class='reveal__cover-section reveal__30'></div> <div class='reveal__cover-section reveal__20'></div> <div class='reveal__cover-section reveal__10'></div> </div> </div>";
revealHtmlBlock = replaceAllInstances(revealHtmlBlock, "{class}", options.id);
$(revealHtmlBlock).appendTo(parent);
contents.appendTo($('.reveal__inner-' + options.id));
//handle options
//delay
if (options.delay === undefined) {
console.log('delay set to 0');
options.delay = 0; //set default
} else {
console.log('delay set to:' + options.delay);
}
var revealElementFunction = function (options) {
$(this).performReveal(options);
};
//background
if (options.background !== undefined) {
$('.reveal__cover-' + options.id + ' .reveal__cover-section').css({'background-color': options.background});
}
//trigger the reveal at the specified time, unless auto is present and set to false
if (options.auto === undefined || (options.auto !== undefined && options.auto)) {
setTimeout(function () {
console.log('call');
revealElementFunction(options);
}, options.delay);
}
//trigger on-visible
if (options.trigger !== undefined) {
var revealOnScreenIntervalIdMap = {};
function uncoverText() {
var onscreen = $('.reveal__inner-box4').isOnScreen();
if ($('.reveal__inner-' + options.id).isOnScreen()) {
$('.reveal__cover-' + options.id).addClass('reveal__uncovered');
revealOnScreenIntervalIdMap[options.id] = window.clearInterval(revealOnScreenIntervalIdMap[options.id]);
}
}
function showTextWhenVisible() {
revealOnScreenIntervalIdMap[options.id] = setInterval(uncoverText, 800);
}
showTextWhenVisible();
}
};
//--------------------
/*
* trigger options:
* immediately (on page load)
* on event, eg. onclick
* on becoming visible, after it scrolls into view, or is displayed after bein ghidden
*
* #param options = {
* id:'box3'
* }
*
*/
$.fn.performReveal = function (options) {
var _performReveal = function () {
$('.reveal__cover-' + options.id).addClass('reveal__uncovered');
};
//allow time for init code to complete
setTimeout(_performReveal, 250);
};
Main JS
jQuery(function () {
//Box 1: reveal immediately - on page load
//NOTE: id does refer to an element id, It is used to
// uniquely refer to the element to be revealed.
var options1 = {
id: 'box1',
background: '#008d35'
};
$('.box1').initReveal(options1);
//------------------------
//Box 2: reveal after specified delay
var options2 = {
id: 'box2'
, delay: 3000
, background: '#008d35'
};
$('.box2').initReveal(options2);
//------------------------
//Box 3: reveal on event - eg. onclick
var options3 = {
id: 'box3'
, auto: false
};
var box3 = $('.box3');
box3.initReveal(options3);
$('.btn-reveal').on('click', function () {
box3.performReveal(options3);
});
//------------------------
//Box 4: Reveal when element scrolls into the viewport
var options4 = {
id: 'box4'
, auto: false
, trigger: 'on-visible'
};
$('.box4').initReveal(options4);
});
//------------------------
//Box 5 reveal
var options5 = {
id: 'box5'
, delay: 2500 ,
background: '#008d35'
};
$('.box5').initReveal(options5);
does anyone have any idea how to make it work word by word and not line by line
Here's a simple approach that you can build on. It creates the needed spans and fades them in based on interval value you set.
var fadeInterval = 300
$('h1').html(function(_, txt){
var words= $.trim(txt).split(' ');
return '<span>' + words.join('</span> <span>') + '</span>';
}).find('span').each(function(idx, elem){
$(elem).delay(idx * fadeInterval).fadeIn();
});
DEMO