Search code examples
jqueryhtmlcsssplitmouse-position

Styling individual characters in HTML strings based on mouse position


I am trying to be able to change css properties of individual characters in a string of text based on the proximity to the mouse position.

Codepen: https://codepen.io/NewbCake/pen/qYXvoo

The idea is to take a string of text and wrap each character in a span with an overall class of ‘single-char’ and a unique class.

The original text string is like this:

<p class='sample-text hover-letter'>This sample text turns red, character by character, when you hover over it with your mouse.</p>

Then it is split into individual character like this:

<span class=“single-char char-0”> T</span>
<span class=“single-char char-1”> h</span>
<span class=“single-char char-2”> i</span>
<span class=“single-char char-3”> s</span>

JS

function arrayMe(string) {

  // For all matching elements
  $(string).each(function() {

    // Get contents of string
    var myStr = $(this).html();

    // Split myStr into an array of characters
    myStr = myStr.split("");

    // Build an html string of characters wrapped in  tags with classes
    var myContents = "";
    for (var i = 0, len = myStr.length; i < len; i++) {
        myContents += '<span class="single-char char-' + i + '">' + myStr[i] + '</span>';
    }

    // Replace original string with constructed html string
    $(this).html(myContents);
console.log(i)
});
(function() {

  var mX, mY, distance,
    $distanceSpan_red = $('#distance_blue span'),
    $distanceSpan_blue = $('#distance_red span'),
    $element0 = $('.char-0'),
    $element1 = $('.char-1');
    $element2 = $('.char-2');
    $element3 = $('.char-3');
    $element4 = $('.char-4');

function calculateDistance(elem, mouseX, mouseY) {
return Math.floor(Math.sqrt(Math.pow(mouseX - (elem.offset().left + (elem.width() / 2)), 2) + Math.pow(mouseY - (elem.offset().top + (elem.height() / 2)), 2)));
}

$(document).mousemove(function(e) {
  mX = e.pageX;
  mY = e.pageY;

  distance0 = calculateDistance($element0, mX, mY);
  distance1 = calculateDistance($element1, mX, mY);
  distance2 = calculateDistance($element2, mX, mY);
  distance3 = calculateDistance($element3, mX, mY);
  distance4 = calculateDistance($element4, mX, mY);


  $element0.css({'font-size': distance0 + 'px'});
  $element1.css({'font-size': distance1 + 'px'});
  $element2.css({'font-size': distance2 + 'px'});
  $element3.css({'font-size': distance3 + 'px'});
  $element4.css({'font-size': distance4 + 'px'});
});
})();
}
// Calling arrayMe on page load, on class "sample-text"
$('document').ready(function() {
  var myStringType = $('.sample-text');
  arrayMe(myStringType);
});

What I am struggling with is how to make the code be flexible and work dynamically. Irrespective of the amount of text, it should be able to measure the distance from the mouse position to each letter's unique class then store that as a distance value then map that distance value to a css property value.

Any help will be appreciated!


Solution

  • I restructure your code to make a working example. You need to make an array based on your class single-char so then you can loop it and don hard code the quantity of characters.

    I comment you calculateDistance() return as the math is a little funky. But with this example you can see how all the characters are affected

      $(document).mousemove(function(e) {
        var mX = e.pageX;
        var mY = e.pageY;
        $('.single-char').each(function(){
          $(this).css({'font-size': calculateDistance(this, mX, mY) + 'px'});
        });                    
      });
    

    You can target all the chars with $('common-class') and then loop them with .each().

    Hope this helps :)

    function arrayMe(string){
    	$(string).each(function() {
    		var myStr = $(this).html();
    		myStr = myStr.split("");
    		var myContents = "";
    		for (var i = 0, len = myStr.length; i < len; i++) {
    			myContents += '<span class="single-char char-' + i + '">' + myStr[i] + '</span>';
    		}
    		$(this).html(myContents);
        console.log(i);
    	});
    }
    
    
    
     function calculateDistance(elem, mouseX, mouseY) {
        // return Math.floor(Math.sqrt(Math.pow(mouseX - ($(elem).offset().left + ($(elem).width() / 2)), 2) + Math.pow(mouseY - ($(elem).offset().top + ($(elem).height() / 2)), 2)));
       return mouseX;
      }
    
    
      $(document).mousemove(function(e) {
        var mX = e.pageX;
        var mY = e.pageY;
        $('.single-char').each(function(){
          $(this).css({'font-size': calculateDistance(this, mX, mY) + 'px'});
        });                    
      });
    
    
    $('document').ready(function() {
    	var myStringType = $('.sample-text');
    	arrayMe(myStringType);
    });
    .single-char:hover {
    	color:red;
    	cursor:pointer;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <p class='sample-text hover-letter'>This sample text turns red, character by character, when you hover over it with your mouse.</p>

    This code has been added to help the OP after a follow up comment.

    function arrayMe(string){
    	$(string).each(function() {
    		var myStr = $(this).html();
    		myStr = myStr.split("");
    		var myContents = "";
    		for (var i = 0, len = myStr.length; i < len; i++) {
    			myContents += '<span class="single-char char-' + i + '">' + myStr[i] + '</span>';
    		}
    		$(this).html(myContents);
        console.log(i);
    	});
    }
    
    
    
     function calculateDistance(elem, mouseX, mouseY) {
        // return Math.floor(Math.sqrt(Math.pow(mouseX - ($(elem).offset().left + ($(elem).width() / 2)), 2) + Math.pow(mouseY - ($(elem).offset().top + ($(elem).height() / 2)), 2)));
       return mouseX;
      }
    
    
    
    
    $('document').ready(function() {
    	var myStringType = $('.sample-text');
    	arrayMe(myStringType);
      
        $('.single-char').hover(function(e) {
          var charNumber = $(this).attr('class').split('-')[2];
          $('.single-char').each(function(){
           $(this).css({'font-size': 12 + 'px'});
          }); 
        $(this).css({'font-size': 36 + 'px'});           
      });
    });
    .single-char:hover {
    	color:red;
    	cursor:pointer;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <p class='sample-text hover-letter'>This sample text turns red, character by character, when you hover over it with your mouse.</p>

    This is a second follow up snippet, to demostrate the funkiness of the math.

    function arrayMe(string){
    	$(string).each(function() {
    		var myStr = $(this).html();
    		myStr = myStr.split("");
    		var myContents = "";
    		for (var i = 0, len = myStr.length; i < len; i++) {
    			myContents += '<span class="single-char char-' + i + '">' + myStr[i] + '</span>';
    		}
    		$(this).html(myContents);
        console.log(i);
    	});
    }
    
    
    
     function calculateDistance(elem, mouseX, mouseY) {
        return Math.floor(Math.sqrt(Math.pow(mouseX - ($(elem).offset().left + ($(elem).width() / 2)), 2) + Math.pow(mouseY - ($(elem).offset().top + ($(elem).height() / 2)), 2)));
      }
    
    
    
    
    $('document').ready(function() {
    	var myStringType = $('.sample-text');
    	arrayMe(myStringType);
      
        $('.single-char').hover(function(e) {
          var mX = e.pageX;
          var mY = e.pageY;
          var charNumber = $(this).attr('class').split('-')[2];
          $('.single-char').each(function(){
           $(this).css({'font-size': calculateDistance($(this), mX, mY) + 'px'});
          });      
      });
    });
    .single-char:hover {
    	color:red;
    	cursor:pointer;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <p class='sample-text hover-letter'>This sample text turns red, character by character, when you hover over it with your mouse.</p>