Move each character of a div based on mouse movement

前端 未结 2 1638
一生所求
一生所求 2021-02-01 10:17

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 use

相关标签:
2条回答
  • 2021-02-01 10:51

    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

    0 讨论(0)
  • 2021-02-01 10:56

    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. :)

    0 讨论(0)
提交回复
热议问题