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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With