Jacob Farenci
Jacob Farenci

Reputation: 119

Unwanted HTML element flickering

I was working on a quick pen for a project when I ran into flickering issues when dragging an element across an image I'm using. Not really sure whats going on here, the problem doesn't seem to occur when you initially load the pen and pan over it the first time, but after that it starts bugging out.

Link to Pen.

Snippet Demo:

$(document).bind('mousemove', function(e){
    $('.tagger').css({
       left:  e.pageX - 55,
       top:   e.pageY - 55
    });
});

$('#crowd').hover(function(){
  $('.tagger').show();
});

$('#crowd').mouseleave(function(){
  $('.tagging').attr('class', 'tagger');
  $('.tagger').hide();
});

$('#crowd').click(function(){
  $('.tagging').attr('class', 'tagger');
});

$('.tagger').click(function(){
  $('.tagger').attr('class', 'tagging');  
});

$(document).on('click', '.tagging li', function(){
  alert($(event.target).text());
});
.tagger {
  top: 0px;
  left: 0px;
  position: absolute;
  z-index: 3;
}

.tagger .frame {
  position: relative;
  height: 100px;
  width: 100px;
  padding: 0px;
  border: 5px;
  border-style: solid;
  border-color: red;
}

.tagger .name {
  display: none;
  position: relative;
  top: -5px;
  height: 90px;
  width: 90px;
  padding: 5px;
  border: 5px;
  border-style: solid;
  border-color: red;
  background-color: white;
}

.tagger .name ul {
  list-style: none;
  padding: 0px;
  margin: 0px;
  display: inline-block;
}







.tagging {
  position: absolute;
  z-index: 3;
}

.tagging .frame {
  position: relative;
  height: 100px;
  width: 100px;
  padding: 0px;
  border: 5px;
  border-style: solid;
  border-color: red;
}

.tagging .name {
  position: relative;
  top: -5px;
  height: 90px;
  width: 90px;
  padding: 5px;
  border: 5px;
  border-style: solid;
  border-color: red;
  background-color: white;
}

.tagging .name ul {
  list-style: none;
  padding: 0px;
  margin: 0px;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <img id="crowd" src="https://s3.amazonaws.com/viking_education/web_development/web_app_eng/photo_tagging_small.png" height="600">
</div>
  
<div class="tagger">
  <div class="frame"></div>
  
  <div class="name">
    <ul>
      <li>One</li>
      <li>Two</li>
      <li>Three</li>
      <li>Fork</li>
      <li>Fyve</li>
    </ul>
  </div>
  
</div>

$(document).bind('mousemove', function(e){
    $('.tagger').css({
       left:  e.pageX - 55,
       top:   e.pageY - 55
    });
});

$('#crowd').hover(function(){
  $('.tagger').show();
});

$('#crowd').mouseleave(function(){
  $('.tagging').attr('class', 'tagger');
  $('.tagger').hide();
});

$('#crowd').click(function(){
  $('.tagging').attr('class', 'tagger');
});

$('.tagger').click(function(){
  $('.tagger').attr('class', 'tagging');  
});

$(document).on('click', '.tagging li', function(){
  alert($(event.target).text());
});

Upvotes: 8

Views: 1473

Answers (3)

Temani Afif
Temani Afif

Reputation: 273523

The hover effect consider the cursor and actually your are moving an element with the cursor so what's happening is this:

  1. You start inside the .tagger element and everything is ok as the cursor is on the .tagger element. No event on the #crowd as the cursor never touched/hovered the #crowd until now.

  2. Once you click or you do something that bring the cursor on #crowd you trigger the hover effect which mean that if you leave you will trigger the mouseleave!

  3. So you hover again on the element .tagger and you trigger the mouseleave as expected.
  4. The element disappear (because of what written in the handler of mouseleave) and the cursor is now on #crowd and you trigger again the hover!
  5. The element .tagger appear again, the cursor is on it and you trigger the mouseleave of #croud and so on ...

The flicker is the infinite sequence (4) (5) (4) (5) (4) ...


To fix this you may change the logic as follow. No need to apply the hide/show function, you can simply wrap the image and .tagger element inside the same wrapper and apply overflow:hidden then keep only the click events.

Here is the full code (I made the image smaller so we can see it in the reduced snippet)

$(document).bind('mousemove', function(e){
    $('.tagger').css({
       left:  e.pageX - 55,
       top:   e.pageY - 55
    });
});


$('#crowd').hover(function(){
  $('.tagging').attr('class', 'tagger');
});

$('.tagger').click(function(){
  $('.tagger').attr('class', 'tagging');  
});

$(document).on('click', '.tagging li', function(){
  alert($(event.target).text());
});
.tagger {
  top: 0px;
  left: 0px;
  position: absolute;
  z-index: 3;
}

.tagger .frame {
  position: relative;
  height: 100px;
  width: 100px;
  padding: 0px;
  border: 5px;
  border-style: solid;
  border-color: red;
}

.tagger .name {
  display: none;
  position: relative;
  top: -5px;
  height: 90px;
  width: 90px;
  padding: 5px;
  border: 5px;
  border-style: solid;
  border-color: red;
  background-color: white;
}

.tagger .name ul {
  list-style: none;
  padding: 0px;
  margin: 0px;
  display: inline-block;
}







.tagging {
  position: absolute;
  z-index: 3;
}

.tagging .frame {
  position: relative;
  height: 100px;
  width: 100px;
  padding: 0px;
  border: 5px;
  border-style: solid;
  border-color: red;
}

.tagging .name {
  position: relative;
  top: -5px;
  height: 90px;
  width: 90px;
  padding: 5px;
  border: 5px;
  border-style: solid;
  border-color: red;
  background-color: white;
}

.tagging .name ul {
  list-style: none;
  padding: 0px;
  margin: 0px;
  display: inline-block;
}

.container {
  overflow:hidden;
  position:relative;
  display:inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <img id="crowd" src="https://s3.amazonaws.com/viking_education/web_development/web_app_eng/photo_tagging_small.png" width='400' height="300">
  
<div class="tagger">
  <div class="frame"></div>
  
  <div class="name">
    <ul>
      <li>One</li>
      <li>Two</li>
      <li>Three</li>
      <li>Fork</li>
      <li>Fyve</li>
    </ul>
  </div>
  
</div>
</div>

Upvotes: 3

Randy Casburn
Randy Casburn

Reputation: 14175

You continuously hide() and show() .tagger repeatedly. mouseleave hides and :hover shows.

there are two ways to fix this:

  1. move the mouseover effect inside the #crowd .hover()

  2. delete the .delete() call within the .mouseleave handler

Also, a note: The jQuery .hover() method takes two callbacks: 1. for the mouseenter 2. for the mouseleave

So the code could be changed a bit in that regard too.

Upvotes: 0

Clayton Engle
Clayton Engle

Reputation: 581

You are assuming .tagger is JUST the border you've drawn. In actuality, there is an invisible box there. The invisible box is on top of #crowd. When .tagger loads, you are no longer hovering over #crowd, you are hovering over .tagger, which is hovering over #crowd.

To fix it, you may change .tagger from one large box around the mouse, to 4 skinny boxes, so that there is nothing directly below the mouse.

Upvotes: 0

Related Questions