So I'm trying to animate a div but I'm not sure what I'm doing wrong here. The following code works just fine on the latest Safari and Chrome but not on Internet Explorer and Firefox.
On Firefox, the error being el.animate is not a function
Any suggestions/solutions?
var slowMo = false;
var dur = slowMo ? 5000 : 500;
function $(id) {
return document.getElementById(id);
}
var players = {};
var hue = 0;
function addTouch(e) {
var el = document.createElement('div');
el.classList.add('ripple');
var color = 'hsl(' + (hue += 70) + ',100%,50%)';
el.style.background = color;
var trans = 'translate(' + e.pageX + 'px,' + e.pageY + 'px) '
console.log(trans);
var player = el.animate([{
opacity: 0.5,
transform: trans + "scale(0) "
}, {
opacity: 1.0,
transform: trans + "scale(2) "
}], {
duration: dur
});
player.playbackRate = 0.1;
players[e.identifier || 'mouse'] = player;
document.body.appendChild(el);
player.onfinish = function() {
if (!document.querySelector('.ripple ~ .pad')) each(document.getElementsByClassName('pad'), function(e) {
e.remove();
});
el.classList.remove('ripple');
el.classList.add('pad');
}
}
function dropTouch(e) {
players[e.identifier || 'mouse'].playbackRate = 1;
}
function each(l, fn) {
for (var i = 0; i < l.length; i++) {
fn(l[i]);
}
}
document.body.onmousedown = addTouch;
document.body.onmouseup = dropTouch;
document.body.ontouchstart = function(e) {
e.preventDefault();
each(e.changedTouches, addTouch);
};
document.body.ontouchend = function(e) {
e.preventDefault();
each(e.changedTouches, dropTouch);
};
var el = document.body;
function prevent(e) {
e.preventDefault();
}
el.addEventListener("touchstart", prevent, false);
el.addEventListener("touchend", prevent, false);
el.addEventListener("touchcancel", prevent, false);
el.addEventListener("touchleave", prevent, false);
el.addEventListener("touchmove", prevent, false);
function fakeTouch() {
var touch = {
pageX: Math.random() * innerWidth,
pageY: Math.random() * innerHeight,
identifier: 'fake_' + Math.random() + '__fake'
}
addTouch(touch);
var length = Math.random() * 1000 + 500;
setTimeout(function() {
dropTouch(touch);
}, length)
setTimeout(function() {
fakeTouch();
}, length - 100)
}
if (location.pathname.match(/fullcpgrid/i)) fakeTouch(); //demo in grid
.ripple {
position: absolute;
width: 100vmax;
height: 100vmax;
top: -50vmax;
left: -50vmax;
border-radius: 50%;
}
body {
overflow: hidden;
}
.pad {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
<div class="pad"></div>
Code thanks to Kyle
So I took a different approach to achieve the same result. I think this one is a lot more straightforward and works in all browsers.
https://jsfiddle.net/cbrmuxcq/1/
Though there is a slight issue and I'm not sure what causes it. If I don't wait (by using setTimeout()), the transition doesn't happen but by setting a timeout it does. If anyone can spot the issue, I'll fix the fiddle and update my answer accordingly.
Related
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.
To see a working example simply copy code into notepad++ and run in chrome as a .html file, I have had trouble getting a working example in snippet or code pen, I would have given a link to those websites if I could get it working in them.
The QUESTION is; once I fire the laser once it behaves exactly the way I want it to. It increments with lzxR++; until it hits boarder of the game arena BUT if I hit the space bar WHILST the laser is moving the code iterates again and tries to display the laser in two places at once which looks bad and very choppy, so how can I get it to work so the if I hit the space bar a second time even whilst the laser was mid incrementation - it STOPS the incrementing and simply shoots a fresh new laser without trying to increment multiple lasers at once???
below is the Code:
<html>
<head>
<style>
#blueCanvas {
position: absolute;
background-color: black;
width: 932px;
height: 512px;
border: 1px solid black;
top: 20px;
left: 20px;
}
#blueBall {
position: relative;
background-color: white;
border: 1px solid blue;
width: 10px;
height: 10px;
border-radius: 100%;
top: 0px;
left: 0px;
}
#laser {
position: absolute;
background-color: white;
border: 1px solid blue;
width: 10px;
height: 1px;
top: 10px;
left: 10px;
}
#pixelTrackerTop {
position: absolute;
top: 530px;
left: 20px;
}
#pixelTrackerLeft {
position: absolute;
top: 550px;
left: 20px;
}
</style>
<title>Portfolio</title>
<script src="https://ajax.googleapis.com/
ajax/libs/jquery/1.12.4/jquery.min.js">
</script>
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
document.addEventListener("keydown", keyBoardInput);
var topY = 0;
var leftX = 0;
var lzrY = 0;
var lzrX = 0;
function moveUp() {
var Y = document.getElementById("blueBall");
topY = topY -= 1;
Y.style.top = topY;
masterTrack();
if (topY < 1) {
topY = 0;
Y.style.top = topY;
};
stopUp = setTimeout("moveUp()", 1)
/**allows for progression of speed with additional key strokes**/
topStop();
stopConflictYup();
console.log('moveUp');
};
function moveDown() {
var Y = document.getElementById("blueBall");
topY = topY += 1;
Y.style.top = topY;
masterTrack();
if (topY > 500) {
topY = 500;
Y.style.top = topY;
};
stopDown = setTimeout("moveDown()", 1)
/**allows for progression of speed with additional key strokes**/
topStop();
stopConflictYdown();
console.log('moveDown');
};
function moveLeft() {
var X = document.getElementById("blueBall");
leftX = leftX -= 1;
X.style.left = leftX;
masterTrack();
if (leftX < 1) {
leftX = 0;
Y.style.leftX = leftX;
};
stopLeft = setTimeout("moveLeft()", 1)
/**allows for progression of speed with additional key strokes**/
leftStop();
stopConflictXleft();
console.log('moveLeft');
};
function moveRight() {
var X = document.getElementById("blueBall");
leftX = leftX += 1;
X.style.left = leftX;
masterTrack();
if (leftX > 920) {
leftX = 920;
Y.style.leftX = leftX;
};
stopRight = setTimeout("moveRight()", 1)
/**allows for progression of speed with additional key strokes**/
leftStop();
stopConflictXright();
console.log('moveRight');
};
function masterTrack() {
var pxY = topY;
var pxX = leftX;
document.getElementById('pixelTrackerTop').innerHTML =
'Top position is ' + pxY;
document.getElementById('pixelTrackerLeft').innerHTML =
'Left position is ' + pxX;
};
function topStop() {
if (topY <= 0) {
clearTimeout(stopUp);
console.log('stopUp activated');
};
if (topY >= 500) {
clearTimeout(stopDown);
console.log('stopDown activated');
};
};
function leftStop() {
if (leftX <= 0) {
clearTimeout(stopLeft);
console.log('stopLeft activated');
};
if (leftX >= 920) {
clearTimeout(stopRight);
console.log('stopRight activated');
};
};
function stopConflictYup() {
clearTimeout(stopDown);
};
function stopConflictYdown() {
clearTimeout(stopUp);
};
function stopConflictXleft() {
clearTimeout(stopRight);
};
function stopConflictXright() {
clearTimeout(stopLeft);
};
function shootLaser() {
var l = document.getElementById("laser");
var lzrY = topY;
var lzrX = leftX;
fireLaser();
function fireLaser() {
l.style.left = lzrX; /**initial x pos **/
l.style.top = topY; /**initial y pos **/
var move = setInterval(moveLaser, 1);
/**continue to increment laser unless IF is met**/
function moveLaser() { /**CALL and start the interval**/
var bcrb = document.getElementById("blueCanvas").style.left;
if (lzrX > bcrb + 920) {
/**if the X axis of the laser goes beyond the
blueCanvas 0 point by 920 then stop incrementing the laser on its X
axis**/
clearInterval(move);
/**if statement was found true so stop increment of laser**/
} else {
lzrX++;
l.style.left = lzrX;
};
};
};
};
function keyBoardInput() {
var i = event.keyCode;
if (i == 32) {
shootLaser();
};
if (i == 38) {
if (topY > 0) {
moveUp();
};
};
if (i == 40) {
if (topY < 500) {
moveDown();
};
};
if (i == 37) {
if (leftX > 0) {
moveLeft();
};
};
if (i == 39) {
if (leftX < 920) {
moveRight();
};
};
};
/**
!! gradual progression of opacity is overall
!! being able to speed up element is best done with setTimout
!! setInterval is constant regards to visual speed
!! NEXT STEP IS ARRAYS OR CLASSES
IN ORDER TO SHOOT MULITPLE OF SAME ELEMENT? MAYBEE?
var l = document.getElementById("laser");
lzrX = lzrX += 1;
l.style.left = lzrX;
lzrY = topY += 1;
l.style.top = lzrY;
**/
</SCRIPT>
</head>
<div id="blueCanvas">
<div id="laser"></div>
<div id="blueBall">
</div>
</div>
<p id="pixelTrackerTop">Top position is 0</p>
<br>
<p id="pixelTrackerLeft">Left position is 0</p>
</body>
</html>
Solved the problem with using a variable called "g" and incrementing it once the laser is shot!
var g = 0;
function keyBoardInput() {
var i = event.keyCode;
if (i == 32) {
if (g < 1) {
shootLaser();
g++;
};
};
Basically, the webticket only goes to about a little over 2/5ths of the screen, I'm trying to figure out how I can stretch the width out so that it covers the entire screen's width.
Fiddle: http://fiddle.jshell.net/Wf43X/56/light/
Javascript:
/*!
* webTicker 1.3
* Examples and documentation at:
* http://jonmifsud.com
* 2011 Jonathan Mifsud
* Version: 1.2 (26-JUNE-2011)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
* Requires:
* jQuery v1.4.2 or later
*
*/
(function($) {
var globalSettings = new Array();
var methods = {
init: function(settings) { // THIS
settings = jQuery.extend({
travelocity: 0.05,
direction: 1,
moving: true
}, settings);
globalSettings[jQuery(this).attr('id')] = settings;
return this.each(function() {
var $strip = jQuery(this);
$strip.addClass("newsticker")
var stripWidth = 0;
var $mask = $strip.wrap("<div class='mask'></div>");
$mask.after("<span class='tickeroverlay-left'> </span><span class='tickeroverlay-right'> </span>")
var $tickercontainer = $strip.parent().wrap("<div class='tickercontainer'></div>");
$strip.find("li").each(function(i) {
stripWidth += jQuery(this, i).outerWidth(true);
});
$strip.width(stripWidth + 200); //20 used for ie9 fix
function scrollnews(spazio, tempo) {
if (settings.direction == 1) $strip.animate({
left: '-=' + spazio
}, tempo, "linear", function() {
$strip.children().last().after($strip.children().first());
var first = $strip.children().first();
var width = first.outerWidth(true);
var defTiming = width / settings.travelocity;
//$strip.css("left", left);
$strip.css("left", '0');
scrollnews(width, defTiming);
});
else $strip.animate({
right: '-=' + spazio
}, tempo, "linear", function() {
$strip.children().last().after($strip.children().first());
var first = $strip.children().first();
var width = first.outerWidth(true);
var defTiming = width / settings.travelocity;
//$strip.css("left", left);
$strip.css("right", '0');
scrollnews(width, defTiming);
});
}
var first = $strip.children().first();
var travel = first.outerWidth(true);
var timing = travel / settings.travelocity;
scrollnews(travel, timing);
$strip.hover(function() {
jQuery(this).stop();
}, function() {
if (globalSettings[jQuery(this).attr('id')].moving) {
var offset = jQuery(this).offset();
var first = $strip.children().first();
var width = first.outerWidth(true);
var residualSpace;
if (settings.direction == 1) residualSpace = parseInt(jQuery(this).css('left').replace('px', '')) + width;
else residualSpace = parseInt(jQuery(this).css('right').replace('px', '')) + width;
var residualTime = residualSpace / settings.travelocity;
scrollnews(residualSpace, residualTime);
}
});
});
},
stop: function() {
if (globalSettings[jQuery(this).attr('id')].moving) {
globalSettings[jQuery(this).attr('id')].moving = false;
return this.each(function() {
jQuery(this).stop();
});
}
},
cont: function() { // GOOD
if (!(globalSettings[jQuery(this).attr('id')].moving)) {
globalSettings[jQuery(this).attr('id')].moving = true;
var settings = globalSettings[jQuery(this).attr('id')];
return this.each(function() {
var $strip = jQuery(this);
function scrollnews(spazio, tempo) {
if (settings.direction == 1) $strip.animate({
left: '-=' + spazio
}, tempo, "linear", function() {
$strip.children().last().after($strip.children().first());
var first = $strip.children().first();
var width = first.outerWidth(true);
var defTiming = width / settings.travelocity;
//$strip.css("left", left);
$strip.css("left", '0');
scrollnews(width, defTiming);
});
else $strip.animate({
right: '-=' + spazio
}, tempo, "linear", function() {
$strip.children().last().after($strip.children().first());
var first = $strip.children().first();
var width = first.outerWidth(true);
var defTiming = width / settings.travelocity;
//$strip.css("left", left);
$strip.css("right", '0');
scrollnews(width, defTiming);
});
}
var offset = jQuery(this).offset();
var first = $strip.children().first();
var width = first.outerWidth(true);
var residualSpace;
if (settings.direction == 1) residualSpace = parseInt(jQuery(this).css('left').replace('px', '')) + width;
else residualSpace = parseInt(jQuery(this).css('right').replace('px', '')) + width;
var residualTime = residualSpace / settings.travelocity;
scrollnews(residualSpace, residualTime);
});
}
}
};
$.fn.webTicker = function(method) {
// Method calling logic
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.webTicker');
}
};
})(jQuery);
jQuery('#webticker').webTicker()
CSS:
.tickercontainer { /* the outer div with the black border */
width: 500px;
height: 27px;
margin: 0;
padding: 0;
overflow: hidden;
}
.tickercontainer .mask { /* that serves as a mask. so you get a sort of padding both left and right */
position: relative;
top: 8px;
height: 18px;
/*width: 718px;*/
overflow: hidden;
}
ul.newsticker { /* that's your list */
position: relative;
/*left: 750px;*/
font: bold 10px Verdana;
list-style-type: none;
margin: 0;
padding: 0;
}
ul.newsticker li {
float: left; /* important: display inline gives incorrect results when you check for elem's width */
margin: 0;
padding-right: 15px;
/*background: #fff;*/
}
Thanks,
Dan
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
I want to display my jQuery validation messages in a tooltip. In order to accomplish this, I started out by adding the following CSS rules to my stylesheet:
fieldset .field-validation-error {
display: none;
}
fieldset .field-validation-error.tooltip-icon {
background-image: url('/content/images/icons.png');
background-position: -32px -192px;
width: 16px;
height: 16px;
display: inline-block;
}
and a very small piece of JS code:
; (function ($) {
$(function() {
var fields = $("fieldset .field-validation-valid, fieldset .field-validation-error");
fields.each(function() {
var self = $(this);
self.addClass("tooltip-icon");
self.attr("rel", "tooltip");
self.attr("title", self.text());
self.text("");
self.tooltip();
});
});
})(jQuery);
The issue is that I now need to capture any event when the validation message changes, I've been looking at the source for jquery.validate.unobtrusive.js, and the method I'd need to hook to is the function onError(error, inputElement) method.
My tooltip plugin works as long as I've an updated title attribute, the issue comes when the field is revalidated, and the validation message is regenerated, I would need to hook into that and prevent the message from being put out there and place it in the title attribute instead.
I want to figure out a way to do this without modifying the actual jquery.validate.unobtrusive.js file.
On a second note, how could I improve this in order to leave the functionality unaltered in case javascript is disabled?
Ok I went with this, just in case anyone runs into this again:
; (function ($) {
$(function() {
function convertValidationMessagesToTooltips(form) {
var fields = $("fieldset .field-validation-valid, fieldset .field-validation-error", form);
fields.each(function() {
var self = $(this);
self.addClass("tooltip-icon");
self.attr("rel", "tooltip");
self.attr("title", self.text());
var span = self.find("span");
if (span.length) {
span.text("");
} else {
self.text("");
}
self.tooltip();
});
}
$("form").each(function() {
var form = $(this);
var settings = form.data("validator").settings;
var old_error_placement = settings.errorPlacement;
var new_error_placement = function() {
old_error_placement.apply(settings, arguments);
convertValidationMessagesToTooltips(form);
};
settings.errorPlacement = new_error_placement;
convertValidationMessagesToTooltips(form); // initialize in case of model-drawn validation messages at page render time.
});
});
})(jQuery);
and styles:
fieldset .field-validation-error { /* noscript */
display: block;
margin-bottom: 20px;
}
fieldset .field-validation-error.tooltip-icon { /* javascript enabled */
display: inline-block;
margin-bottom: 0px;
background-image: url('/content/images/icons.png');
background-position: -32px -192px;
width: 16px;
height: 16px;
vertical-align: middle;
}
I'll just include the tooltip script I have, since it's kind of custom-made (though I based it off someone else's).
; (function ($, window) {
$.fn.tooltip = function (){
var classes = {
tooltip: "tooltip",
top: "tooltip-top",
left: "tooltip-left",
right: "tooltip-right"
};
function init(self, tooltip) {
if ($(window).width() < tooltip.outerWidth() * 1.5) {
tooltip.css("max-width", $(window).width() / 2);
} else {
tooltip.css("max-width", 340);
}
var pos = {
x: self.offset().left + (self.outerWidth() / 2) - (tooltip.outerWidth() / 2),
y: self.offset().top - tooltip.outerHeight() - 20
};
if (pos.x < 0) {
pos.x = self.offset().left + self.outerWidth() / 2 - 20;
tooltip.addClass(classes.left);
} else {
tooltip.removeClass(classes.left);
}
if (pos.x + tooltip.outerWidth() > $(window).width()) {
pos.x = self.offset().left - tooltip.outerWidth() + self.outerWidth() / 2 + 20;
tooltip.addClass(classes.right);
} else {
tooltip.removeClass(classes.right);
}
if (pos.y < 0) {
pos.y = self.offset().top + self.outerHeight();
tooltip.addClass(classes.top);
} else {
tooltip.removeClass(classes.top);
}
tooltip.css({
left: pos.x,
top: pos.y
}).animate({
top: "+=10",
opacity: 1
}, 50);
};
function activate() {
var self = $(this);
var message = self.attr("title");
var tooltip = $("<div class='{0}'></div>".format(classes.tooltip));
if (!message) {
return;
}
self.removeAttr("title");
tooltip.css("opacity", 0).html(message).appendTo("body");
var reload = function() { // respec tooltip's size and position.
init(self, tooltip);
};
reload();
$(window).resize(reload);
var remove = function () {
tooltip.animate({
top: "-=10",
opacity: 0
}, 50, function() {
$(this).remove();
});
self.attr("title", message);
};
self.bind("mouseleave", remove);
tooltip.bind("click", remove);
};
return this.each(function () {
var self = $(this);
self.bind("mouseenter", activate);
});
};
$.tooltip = function() {
return $("[rel~=tooltip]").tooltip();
};
})(jQuery, window);