Change animation css attribute with javascript onmousemove? - javascript

So im making this little trick on my website that when you move your cursor on the screen it changes the speed at which the logo of the site rotates.
For some reason i cannot seem to be able to change the animation attribute of the element im rotating on the fly with js. I also added a textbox to display the mouse X position which im using for the speed of the roation of the logo, and it displays the string correctly so i guess its probably a silly syntax error.
<style type="text/css">
#logorota {
animation: 15s linear 0s normal none infinite rot_inf;
}
#keyframes rot_inf {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
</style>
<body>
<script>
document.captureEvents(Event.MOUSEMOVE);
document.onmousemove = mousePos, logoSpeed;
function mousePos (x) {
var mouseX = x.pageX / 100;
document.mouseMovs.mousePos.value = mouseX + "s linear 0s normal none infinite rot_inf"; //displays the string correctly.
};
function logoSpeed (x)
{
var mouseX = x.pageX / 100;
document.getElementById('logorota').style.animation = mouseX + "s linear 0s normal none infinite rot_inf";
};
</script>
<div>
<img src="logorota.png" id="logorota">
<form name="mouseMovs">
<input type="text" name="mousePos" /> Mouse position <br />
</form>
</div>
</body>
EDIT: Added http://jsfiddle.net/ot4zyp30/

I have a solution here for webkit, working right. It is a lil tricky to change these values on the fly.
Attached to 'mousemove', this script adds / removes the animation rule & class continiously and alters some values so it rotates smooth enough.
Theres bunch of stuff you wanna change if you use this. Atleast make sure the stylesheet index is good etc. in this case i use 1 since thats the jsFiddle stylesheet index.
EDIT: works on firefox now too
http://jsfiddle.net/9nj4dgeq/
//
document.addEventListener('mousemove', function(event) {
Rotator.init(event, document.getElementsByClassName("img")[0]);
}, false);
//
var Rotator = {
init: function(event, element_) {
var element = element_,
compatibility = {
prefixes: ["-webkit-", "-moz-"],
},
browserPrefix,
browserEvent = event.clientX,
stylesheet = 0;
for (var k in compatibility) {
if (k === "prefixes") {
for (var i = 0; i < compatibility[k].length; i += 1) {
if (window.getComputedStyle(element, null).getPropertyValue(compatibility[k][i] + "transform") !== null) {
browserPrefix = compatibility.prefixes[i];
}
}
}
}
this.rotate(element, browserPrefix, browserEvent, stylesheet);
},
rotate: function(element_, browserPrefix_, browserEvent_, stylesheet_) {
var element = element_,
className = element.className,
browserPrefix = browserPrefix_,
browserEvent = browserEvent_,
stylesheet = stylesheet_,
blanks = [
"#" + browserPrefix + "keyframes ",
" {from{" + browserPrefix + "transform:rotate( ",
"deg);}to{" + browserPrefix + "transform:rotate(",
"deg);}}",
".",
"{" + browserPrefix + "animation-name:",
";" + browserPrefix + "animation-timing-function:linear;" + browserPrefix + "animation-iteration-count:infinite;" + browserPrefix + "animation-duration:",
"s}"],
name = "rotating" + browserEvent,
speed = String(browserEvent / 100),
transform = window.getComputedStyle(element, null).getPropertyValue(browserPrefix + "transform"),
values, a, b, angle, toAngle;
if (transform !== "none") {
values = transform.split('(')[1];
values = values.split(')')[0];
values = values.split(',');
a = values[0];
b = values[1];
angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
}
toAngle = 360 + angle;
document.styleSheets[stylesheet].insertRule(blanks[0] + name + blanks[1] + angle + blanks[2] +
(function () {
if (!toAngle) {
return 10;
} else {
return toAngle;
}
}()) + blanks[3], 0);
document.styleSheets[stylesheet].insertRule(blanks[4] + className + blanks[5] + name + blanks[6] + speed + blanks[7], 0);
if (document.styleSheets[stylesheet].cssRules.length > 8) {
for (var rules = document.styleSheets[stylesheet].cssRules.length; rules > 2; rules -= 1) {
document.styleSheets[stylesheet].deleteRule([rules] - 1);
}
}
}
}

Related

program flow animating in javascript

Hello I am having errors with my code:
https://jsfiddle.net/wzhm2whj/
<script>
//Initial Global variables
var mainloop_frame_time = 34;
var top = 0;
var rootMenu = document.getElementById('menu');
var rootMenuDivs = rootMenu.getElementsByTagName('div')[0];
var rootListDivs = rootMenuDivs.getElementsByTagName('ul')[0];
var childDivs = rootListDivs.getElementsByTagName('div');
var childDiv = childDivs[0];
var childDiv_counter = 0;
var child_change_flag = true;
var child_index_increment = 0;
var child_index_amount = childDivs.length;
//var child_animation_keyframe = 0;
var frame = 0;
var childDiv_tmp1_position = 0;
//finding the web browsers viewport size.
var elem = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body;
var client_height = elem.clientHeight;
var process_array = new Array();
//Initial styling
for (var i = 0; i < childDivs.length; i++) {
var childDiv = childDivs[0];
childDiv.style.backgroundColor = "antiquewhite";
}
var childDiv = childDivs[0];
//rotate function variables
var rotate_div;
var rotate_passed_deg;
var rotate_deg_stop;
var rotate_results;
var rotate_current_deg = 0;
var speed_modifier = 1;
var tmp1_speed = 0;
//case flags
case2_flag = -1;
case3_flag = -1;
//This may not be needed >>> If not, put all code in mainloop.
var processes_logic = function() {
switch (frame) {
case 0:
process_array.push(menu_child0);
break;
//this case is when the previous case is 80% done
case 28:
rootMenu.style.transformOrigin = "top left";
process_array.push(menu_slant);
break;
case 35:
//Added the ability for paramaters, all push paramaters here are: function, menu_index, position, speed, tmp as flag for switching to next menu,
//process_index used to give the process index as refrence to delete..
window.alert(process_array.length);
process_array.push(new Array(menu_div_slide_out, child_index_amount - 1, 0, 0, 0, process_array.length-1));
break;
}
}
var initiate_all_processes = function() {
for (var i = 0; i < process_array.length; i++) {
//Added the ability for paramaters, considerer removing as its not used atm, or revising.
if (process_array[i] != undefined && process_array[i] != null && process_array[i] != "") {
if (process_array[i].length < 6) {
process_array[i]();
} else {
process_array[i][0](process_array[i][5]);
}
}
}
}
function menu_div_slide_out(process_index) {
/*process_array[process_index][
0 = function,
1 = current menu item (index length working backwards)
2 = position,
3 = speed,
4 = tmp,
5 = refrence to this process in array] */
//for debuging purposes to see if a ChildDiv is not devined, what process index is being pointed to.
//window.alert('Process index ' + process_index);
//!!!!!!!! You are probably mixing up how you are setting process index! try +1
process_array[process_index][2] += 3.5 + (process_array[process_index][3] * 1.7);
process_array[process_index][3] += (speed_modifier * .3);
childDivs[process_array[process_index][1]].style.left = process_array[process_index][2] + 'px';
if (process_array[process_index][2] > 100 && process_array[process_index][4] && process_array[process_index][1] > 0) {
// window.alert('CCC');
process_array[process_index][4] = true;
//Add another process at ever 100pxs
process_array.push(new Array(menu_div_slide_out, process_array[process_index][1] - 1, 0, 0, false, process_array.length-1));
//debugger;
} else
if (process_array[process_index][2] >= (900 - (process_array[process_index][2] / 20))) {
childDivs[process_array[process_index][1]].remove();
//process_array.splice(process_array[process_index][5], 1);
}
}
function menu_slant() {
rotate_return = rotate(rootMenu, .1 + (tmp1_speed), 27);
tmp1_speed += (speed_modifier * .5);
if (rotate_return === true) {
/////////////This can be unremoved because there is more animation, perhaps. or can be done in another key frame.
tmp1_speed = 0;
rotate_current_deg = 0;
remove_process(menu_slant);
} else {
if (rotate_return / 27 * 100 >= 60 && case3_flag < 0) {
case2_flag = frame;
}
}
}
var menu_child0 = function() {
childDiv_tmp1_position += 3 + (tmp1_speed * 1.7);
childDiv.style.top = childDiv_tmp1_position + 'px';
rotate(childDiv, .2 + (tmp1_speed), 170);
tmp1_speed += (speed_modifier * .7);
if (childDiv_tmp1_position / client_height * 100 >= 80 && case2_flag < 0) {
case2_flag = frame;
}
if (childDiv_tmp1_position >= client_height) {
childDiv.style.visibility = 'hidden';
tmp1_speed = 0;
childDiv_tmp1_position = 0;
rotate_current_deg = 0;
//may be bloated >>
remove_process(menu_child0);
}
}
function remove_process(index) {
var index_tmp = process_array.indexOf(index);
if (index_tmp >= 0) {
process_array.splice(index_tmp, 1);
}
}
function rotate(rotate_div, rotate_passed_deg, rotate_passed_deg_stop) {
rotate_current_deg += rotate_passed_deg;
rotate_deg = rotate_current_deg < rotate_passed_deg_stop ? rotate_current_deg : rotate_passed_deg_stop;
rotate_div.style.webkitTransform = 'rotate(' + rotate_deg + 'deg)';
rotate_div.style.mozTransform = 'rotate(' + rotate_deg + 'deg)';
rotate_div.style.msTransform = 'rotate(' + rotate_deg + 'deg)';
rotate_div.style.oTransform = 'rotate(' + rotate_deg + 'deg)';
rotate_div.style.transform = 'rotate(' + rotate_deg + 'deg)';
if (rotate_current_deg >= rotate_passed_deg_stop) {
return true;
} else {
return rotate_current_deg;
}
}
//main loop for the animation
var mainloop = function() {
processes_logic();
initiate_all_processes();
frame++;
}
var loop_interval = setInterval(mainloop, mainloop_frame_time);
</script>
I am trying to animate my website falling apart but I am having a hard time articulation this into code. I thought of running the animation in a loop, creating events at specific frames and reusing some codes as functions. I have a rotate function which works to rotate several things.
THE PROBLEM:
The problem I am having is sliding my menu items one at a time to the right. I want one to slide a bit and the next to start sliding after. I wrote a function to slide an item and then in that function it adds another process to an array for the next menu item to be called and run the same function (with passed interval of who is calling). I do not know how many menu items there will be, thats why I am trying to make it dynamic.
I can get it so that the first mwnu item falls, the menu falls by rotating it (some times if there is an error in the code then it wont rotate, but when there are no errors it works better).
The issue is sliding each menu item.
my website is here: http://clearlove.ca/89-404-error
Can any one help me with why this isnt working, and if there is a better way to do what I am trying to do?

Smooth and fast sprite animation (CSS)

I'm trying to make a game of a Space Invaders using JavaScript/jQuery. Now my problem is I cannot make the spaceship move smoothly on the screen.
I am using a keydown event to change sprite's CSS position by n pixels. When I give it a high value, the sprite moves fast but not smoothly. When I choose to move the sprite by 1px it looks smoother, but is very slow. Any ideas how to approach it?
The live demo is here. Use WSAD keys to move the sprite.
PS I'm not asking for animation libraries. I'd like to achieve it using JavaScript/jQuery only.
$(document).ready(function() {
var xPos, yPos;
var height = $(document).height();
var width = $(document).width();
function move(dir) {
console.log(height + "," + width);
xPos = parseInt($('#sprite').css('left'));
yPos = parseInt($('#sprite').css('top'));
switch (dir) {
case 'up':
if (yPos > 10) { $('#sprite').css('top', yPos - 10 + "px"); }
break;
case 'down':
if (yPos < height-140) { $('#sprite').css('top', yPos + 10 + "px"); }
break;
case 'left':
if (xPos > 10) { $('#sprite').css('left', xPos - 10 + "px"); }
break;
case 'right':
if (xPos < width-140) { $('#sprite').css('left', xPos + 10 + "px"); }
break;
}
}
$(document).keydown(function(event) {
var mykey = String.fromCharCode(event.which);
if (mykey == "W" || mykey == "w") { move('up'); }
if (mykey == "S" || mykey == "s") { move('down') }
if (mykey == "A" || mykey == "a") { move('left') }
if (mykey == "D" || mykey == "d") { move('right') }
});
});
Just add CSS3 transition to your ship :
#sprite{
-webkit-transition : all 0.4s ease-in-out;
-moz-transition : all 0.4s ease-in-out;
-o-transition : all 0.4s ease-in-out;
transition : all 0.4s ease-in-out;
}
However, animating with translate is better than position top/left (article by Paul Irish).
Besides, optimize your code by caching $('#sprite') with
var $sprite = $('#sprite');
function move(dir) {
xPos = parseInt($sprite.css('left'));
yPos = parseInt($sprite.css('top'));
...
If you don't do this (as the code is currently), you force jQuery to go all over the whole DOM many times, every time a key is pressed. If you do, the ship is cached so jQuery doesn't have to look for it every time. I suggest you to have a look at jQache for easy caching.
I give you a pure Javascript snippet that is as simple as possible, so you easily replace the divs with images or animated sprites.
Also the positions you control with Javascript exactly as you want.
For space invader this is ideal, because all ships will move smoothly from one position to the other. It is a misstake from old tween experiences to believe it get slow with Javascript, but the intermediate pixels is not needed to tween. The GPU takes care of it by CSS transitions.
Here is 100 moving divs ...
let d = document, html = "", css3 = "", x, y, z, t = 10, n = 100
for (let i = 0; i < n; i++) {
css3 += "#sprite" + i + " {display:inline-box; position:absolute; width:10px; height:10px; background-color:red; transition:top " + t + "s, left " + t + "s;}"
html += "<div id='sprite" + i + "'></div>"
}
var e = d.createElement('style')
e.innerHTML = css3
d.head.appendChild(e)
var e = d.createElement('div')
e.innerHTML = html
d.body.appendChild(e)
move();
setTimeout(move, 0)
setInterval(move, 1000*t)
function move() {
for (let i = 0; i < n; i++) {
x = 600*Math.random()
y = 200*Math.random()
z = d.getElementById("sprite" + i)
if (z) {
z.style.top = y + "px"
z.style.left = x + "px"
}
}
}
This is more Space Invader like but the code got cluttered ...
let d = document, html = "", css3 = "", t = 2, n = 300
let x, y, z, xx = 40, yy = 40, xxx = 30, yyy = 30
document.write(n + " space invaders, " + t + "s moves by " + xxx + "px")
for (let i = 0; i < n; i++) {
css3 += "body {background:black; color:pink;} #sprite" + i + " {display:inline-box; position:absolute; width:30px; height:30px; background-color:blue; transition:top 1s, left " + t + "s;}"
html += "<img id='sprite" + i + "' src='https://i.gifer.com/PCTg.gif'></img>"
}
var e = d.createElement('style')
e.innerHTML = css3
d.head.appendChild(e)
var e = d.createElement('div')
e.innerHTML = html
setTimeout(function(){d.body.appendChild(e)}, 100)
setInterval(move, 1000*t)
function move() {
if (xxx > 0? xx > 100: xx < 40) {
xx += xxx
xxx = -xxx
yy += 10
}
xx += xxx
for (let i = 0; i < n; i++) {
x = 30*(i % 30) + xx
y = 30*parseInt(i / 30) + yy
z = d.getElementById("sprite" + i)
if (z) {
z.style.top = y + "px"
z.style.left = x + "px"
}
}
}

Move each character of a div based on mouse movement

I'm developing a site and I don't know how to create a javascript animation that looks like this:
I have a div that have some text on it, and when the user moves his mouse over this text, I want each character to move independently of each other, in order to maintain a certain distance from it (the mouse). Also, I want this animation to have rotation, but it isn't that important now. Here's an image explanation:
Here's what I did so far:
HTML:
<div class="div1">Hello World</div>
Javascript:
var chars = $(".div1").html().split('');
$(".div1").empty();
for(var i = 0; i < chars.length; i++){
$(".div1").append("<span class='letter'>"+chars[i]+"</span>");
}
JSFiddle
Can someone help me to achieve this effect? I don't know how to proceed and there's no site or answer that helped me. You can use jQuery or pure JavaScript but, please, keep it simple! Thank you.
Oh here we go, I've found a solution for this.
What I did was using a different class name for each character (.letter + character number) and then created a way of moving the characters depending on the mouse position and distance compared to each character, so, for example, when the distance between the mouse and a character is less than X, and the mouse Y is less than the character Y, then the character will go down.
Thanks to adeneo and Derek
Here's the relevant code:
JavaScript:
var chars = $(".div1").html().split('');
$(".div1").empty();
for (var i = 0; i < chars.length; i++) {
$(".div1").append("<span class='letter" + i + "'>" + chars[i] + "</span>");
$(".letter" + i).css({
"position":"relative",
});
$(".letter" + i).css({
"transition": "0.5s"
});
}
$(document).on("mousemove", function (e) {
for (var i = 0; i < chars.length; i++) {
var x = e.pageX,
y = e.pageY;
var distx = x - $(".letter" + i).offset().left + ($(".letter" + i).width() / 2);
var disty = y - $(".letter" + i).offset().top;
if (Math.abs(distx) < 24 && Math.abs(disty) < 24) {
if (distx > 6 || distx < -6) {
if (x < $(".letter" + i).offset().left) {
$(".letter" + i).css({
"left": + (24 / Math.abs(distx) * Math.abs(distx)),
"position": "relative"
});
} else {
$(".letter" + i).css({
"left": - (24 / Math.abs(distx) * Math.abs(distx)),
"position": "relative"
});
}
}
if (disty > 12 || disty < -12) {
if (y < $(".letter" + i).offset().top + 6) {
$(".letter" + i).css({
"top": + (24 / Math.abs(disty) * Math.abs(disty)),
"position": "relative"
});
} else {
$(".letter" + i).css({
"top": - (24 / Math.abs(disty) * Math.abs(disty)),
"position": "relative"
});
}
}
}
distx = 0;
disty = 0;
}
});
HTML:
<div class="div1">Hello World</div>
Updated JSFiddle with CSS Transitions to improve smoothness
Well since you say yo want to learn, i'll give a code to help you out, but you have to work your way through, i haven't test it, i just wrote it blindly so it propably won't work but might give you a good idea of what must be done.
Html:
<div class="container">
<div id="coolDiv" class="scatterContainer">Hello World</div>
</div>
Css:
*{margin:0;}
span:hover{
color:#0CF;
}
.scatterContainer{
display: inline;
}
.container {
margin: 30px auto;
}
Javascript
LetterScatterer = (function() {
function LetterScatterer(id) {
this.id = id
this.$el = $('#' + this.id);
this.rangeOfaction = 3; // Number of characters to affect
this.maxVerticalMovement = 10; // Value in px
this.minVerticalMovement = 2
this.duration = 100; // In miliseconds
// Event Listeners
this.$el.on(mousemove((function(_this){
return function(e){
var x = e.pageX;
var y = e.pageY;
return _this.scatter(x, y);
}
})(this));
}
LetterScatterer.prototype.splitCharacters = function() {
var nodes = [];
var nodesQ = 0;
var _this = this;
this.chars = $el.text().split('');
$el.empty();
for(var i = 0; i < chars.length; i++){
var markup = "<span class='letter'>"+chars[i]+"</span>";
nodes.push(markup);
}
this.$nodes = $(nodes);
this.nodesWidth = [];
this.$nodes.each(function(){
var width = $(this).outerWidth();
_this.nodesWidth.push(width);
});
$el.append(this.$nodes);
}
LetterScatterer.prototype.scatter = function(x, y) {
var epicenter;
var offset = 0;
var midPoint, farestLeft;
for(var i = 0, len = this.nodesWidth.length; i < len; i++){
offset += this.nodesWidth[i];
if(x <= offset){
epicenter = i;
break;
}
}
leftRange = (this.rangeOfaction - 1) / 2; // We remove one, this is our epicenter, then we get left and right halves
farestLeft = epicenter - leftRange;
for(var i = farestLeft; i < this.rangeOfaction; i++){
this.animateY($node[i]);
}
}
LetterScatterer.prototype.animateY = function(node, verticalDisplacement) {
var $node = $(node);
$node.animate({margin-top: verticalDisplacement + 'px'}, this.duration);
}
return LetterScatterer;
})();
letterScatterer = new LetterScatterer('coolDiv');
What you see in the code is a classlike function, first you pass it the id of the element containing the text that will be scattered. There are some config varaibles, range of action is lets say, if you mouse over one character, how many characters to the left and to the right (also including the current hovered element) should be animated, the max and min verticalMovement, determines how much should move the one that is hovered (max) and those further apart will use min, those in between should interpolate, but i didn't code that far.
We then got a mousemove listener, that calls the method scatter, this method finds which items is currently hovered by adding up each character widht, but now i think about it, it should be easier to just add a listener to the span, and get the current index of that element with the jQuery method index(), then based on that index you animate that one and those in the range. You must create the code that calculates the rotation, and x movement if you want to, but i think i gave you a lot to start, it took me a while to code it, so i hope it helps and this answer satisfies your question. :)

JavaScript: How do I stack rectangle elements tetris style, without using plugins?

I'm making a scheduling calendar. The events are horizontal blocks (Google Cal has vertical ones). And because I have loads of events in one date I want the events to stack onto eachother without wasting any space, like this:
I did find plugins:
http://masonry.desandro.com/
http://isotope.metafizzy.co/
http://packery.metafizzy.co/
But I'm not keen on using a 30kb plugin just to do this simple thing.
To clarify: because this is a timeline, the div-events cannot move left/right, but must fit itself vertically amongst other div-events.
My own solution is a 2.6kb (commented) jQuery script, that uses absolute positioning for events and a div as a container for each row.
This script generates randomly size bars. Each new bar checks for space in each row from top-down. I'm using percentages, because that way calculating bar position against time will be easy (100% / 24h).
http://jsfiddle.net/cj23H/5/
Though works and is efficient enough, it feels bulky. You're welcome to improve.
jQuery code from my jsfiddle:
function rand() {
return Math.floor(Math.random() * 101);
}
function get_target_row(width, left) {
var i = 0;
var target_found = false;
// Loop through all the rows to see if there's space anywhere
while (target_found === false) {
// Define current row selector
var target_i = '.personnel#row' + i;
// Add row if none
if ($(target_i).length === 0) {
$('body').append('<div class="personnel" id="row' + i + '"></div>');
}
// See if there's space
if ($(target_i).children().length === 0) {
target_found = $(target_i);
} else {
var spaceFree = false;
// Check collision for each child
$(target_i).children().each(function () {
// Get left and right coordinates
var thisWidthPx = parseFloat($(this).css('width'), 10);
var thisWidthParentPx = parseFloat($(this).parent().css('width'), 10);
var thisWidth = (thisWidthPx / thisWidthParentPx * 100);
var thisLeftPx = parseFloat($(this).css('left'), 10);
var thisLeftParentPx = parseFloat($(this).parent().css('left'), 10);
var thisLeft = (thisLeftPx / thisWidthParentPx * 100);
var thisRight = thisLeft + thisWidth;
var right = left + width;
// Sexy way for checking collision
if ((right > thisLeft && right < thisRight) || (left < thisRight && left > thisLeft) || (thisLeft > left && thisLeft < right) || (thisRight < right && thisRight > left)) {
spaceFree = false;
return false;
} else {
spaceFree = true;
}
});
// If no children have collided break the loop
if (spaceFree === true) {
target_found = $(target_i);
}
}
i++;
}
// If after all the while loops target is still not found...
if (target_found === false) {
return false;
}
// Else, if target is found, return it.
return target_found;
}
// Generate random bars
for (var i = 0; i < 10; i++) {
var width = rand()/2;
var left = rand()/2;
var right = left + width;
var target = get_target_row(width, left);
target.append('<div class="block" style="width:' + width + '%;position:absolute;left:' + left + '%;background-color:rgba(' + rand() + ',' + rand() + ',' + rand() + ',0.4)" id="bar'+i+'">' + 'b' + i + '</div>');
}
CSS:
.block {
position: absolute;
background-color: rgba(200, 100, 100, 0.4);
height: 32px;
}
.personnel {
position: relative;
float: left;
width: 100%;
height: 33px;
}

jQuery (or other javascript) to stack divs at fixed distance from top of viewport

I would like it so that the as the user scrolls down the page and hits certain "sticky" elements, they add themselves to the top of the page.
I.e., let's say the page has a fixed, 10px high element at the top, then a 50px high Logo (non sticky), then a horizontal navigation bar (sticky), then some other non-sticky elements, then a pager (sticky, allows user to go to next or previous page), etc.
The idea is that some elements are useful all up and down the page, others can just stay at the top. But since they are intercalated, we need a way to stick just the important ones to the top.
So, if you scrolled halfway down the page, the non stick elements would have moved out of view, but the sticky ones would all be stacked at the top below any fixed element. In my example, you'd have 10px high element, nav bar, and pager. The logo would scroll away.
I've come up with some jQuery but it's quirky. If I scroll down slowly, it works. If I scroll down quickly, or hit "page down" on my keyboard, it ends up working incorrectly, with extra space between sticky elements and other errors.
It feels like I'm so close, and yet so far.
Here's what I have.
<style type="text/css">
div.stickert {
/*
padding:20px;
margin:20px 0;*/
/*background:#AAA;
width:190px;*/
position:relative;
top:0px;
}
.sticked {
position:fixed;
/*top:0px;
z-index:100;*/
width:100%;
}
</style>
<!--<script src="http://code.jquery.com/jquery-latest.min.js"></script>-->
<script type="text/javascript">
jQuery(document).ready(function() {
var stupid = jQuery(".stickert");
var startOffset = 0;
var startingZ = 100;
/* var topDone = []; */
/* var pos = second.position(); */
var origOffsets = [];
var heights = [];
var currentOffsets = [];
mWait = jQuery("#m-wait");
mWait.show();
mGraph = mWait.find('p');
mGraph.text('');
jQuery.each(stupid, function(i, object) {
var obj = jQuery(object);
var pos = obj.position();
origOffsets[ i ] = pos.top;
heights[ i ] = obj.height();
}
);
var debug = false;
jQuery(window).scroll(function() {
var windowpos = jQuery(window).scrollTop();
var topOffset = startOffset;
var theZIndex = startingZ;
jQuery.each(stupid, function(i, object) {
var obj = jQuery(object);
console.log(obj);
/*mGraph.append('obj:<br />' + obj);*/
/*var pos = obj.position();*/
/* currentOffsets[ i ] = pos;*/
var tagName = obj.get(0).tagName;
tagName.toLowerCase; /* e.g. "div" or "li" */
var totalOffset = parseInt(origOffsets[ i ],10) - parseInt(startOffset,10) - topOffset; /* I think subtraction is correct */
if(windowpos <= totalOffset /*&& obj.hasClass("sticked") */) {
if( debug ) alert('resetting');
if(obj.hasClass("sticked") ) {
obj.removeClass("sticked");
/*obj.addClass("stickert");*/
obj.css({ top: "0px" });
var removeThis = obj.next(".sticked-padder");
removeThis.remove();
obj.addClass("stickert"); /* put inside if hasclass? */
}
/* return false; */
} else if(windowpos > totalOffset) {
/*if(windowpos >= pos.top) {*/
/*if( debug ) alert("setting sticked");*/
/*if(!(i in topDone)) {*/
if(obj.hasClass("stickert")) {
mGraph.append('Element ' + i + '<br />Made it to the start. zIndex = ' + theZIndex + '</br>'
+ 'topOffset= ' + topOffset + '<br />');
obj.removeClass("stickert");
/*currentOffsets[ i ] = obj.position();*/
topOffset += obj.height();
if( debug ) alert(topOffset);
obj.after('<' + tagName + ' class="sticked-padder" style="height:' + obj.height() + 'px"></div>');
/*topDone[ i ] = "done";*/
obj.css({ top: ( topOffset - heights[ i ] ) + "px"});
obj.addClass("sticked");
obj.css({ zIndex: theZIndex });
theZIndex -=1 ;
mGraph.append('Element ' + i + '<br />Made it to the end. zIndex = ' + theZIndex + '</br>'
+ 'topOffset= ' + topOffset + '<br />');
/* alert(theZIndex);*/
}
}
topOffset += heights[ i ];
});
jQuery(window).scrollTop(windowpos); /* make sure window stays in same place */
/* ssss.html("Distance from top:" + pos.top + "<br />Scroll position: " + windowpos); */
/*if (windowpos >= pos.top) {
stupid.addClass("sticked");
} else {
stupid.removeClass("sticked");
}*/
});
});
</script>
you can check Twitter Bootstrap's affix javascript and re-use it
http://getbootstrap.com/javascript/#affix
source:
https://github.com/twbs/bootstrap/blob/3.0.0-wip/js/affix.js

Categories

Resources