Angular, mouseover speed is choppy?

Viewed 56

I'm trying to create a "tooltip" that follows the mouse around and disappears when it leaves it's location. However, the tooltip created is slow, it doesn't follow my mouse around smoothly and seems choppy. How do I fix this?

https://stackblitz.com/edit/angular-851aej?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html

TS:

export class AppComponent {
  name = 'Angular';

  constructor(private el: ElementRef) {}

  first(e: { pageX: any; pageY: any }) {
    console.log(e.pageX, e.pageY);

    this.el.nativeElement.querySelector('#first').style.left =
      e.pageX.toString() + 'px';
    this.el.nativeElement.querySelector('#first').style.top =
      e.pageY.toString() + 'px';
    this.el.nativeElement.querySelector('#first').classList.add('show');
  }

  second(e: { pageX: any; pageY: any }) {
    this.el.nativeElement.querySelector('#first').style.left = '0px';
    this.el.nativeElement.querySelector('#first').style.top = '0px';

    this.el.nativeElement.querySelector('#first').classList.remove('show');
  }
}

HTML:

<div (mouseover)="first($event)" (mouseleave)="second($event)"class="place-welcome">
<h2>This is a Panel</h2>
<p>Hello my darling</p>
</div>

<div id="first">asdasdasdasd</div>
2 Answers

Mouseover can be an event that trigger many times in a few seconds, for example the cursor moves 1px while still being over the same htmlElement.

Considering that...

  • try to avoid calling console.log always (include a condition of some kind)
  • instead of calling this method every time this.el.nativeElement.querySelector('#first') assign it to a variable en reuse it
let first = this.el.nativeElement.querySelector('#first') ;
first.left = e.pageX.toString() + 'px';
first.style.top = e.pageY.toString() + 'px';
first.classList.add('show');

not only it makes your code more readable, it avoids query over and over to get the same result on each call to onmouseover

Instead of using mouseover and mouseleave, use:

  • mousenter to detect when the mouse enters the div. This is where you display the tooltip.
  • mousemove to detect when the mouse is moved inside the div. This is where you position the tooltip.
  • mouseleave to detect when the mouse leaves the div. This is where you hide the tooltip.

In addition:

  • Don't perform the same element query multiple times in one function, but perform the lookup once and store it in a variable. Possibly, you can even perform the lookup just once on component initialization, but that depends on the further logic of your component.
  • Make sure to set pointer-events to none for the tooltip; if not, you will get interference from the mouse entering and leaving the tooltip.

Putting all of this together, you get the following code:

Component:

import { Component, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  name = 'Angular';

  constructor(private el: ElementRef) {}

  get tooltip() {
    return this.el.nativeElement.querySelector('#first');
  }

  enter() {
    this.tooltip.classList.add('show');
  }

  move(e: { pageX: number; pageY: number }) {
    const tooltipStyle = this.tooltip.style;
    tooltipStyle.left = e.pageX + 'px';
    tooltipStyle.top = e.pageY + 'px';
  }

  leave() {
    this.tooltip.classList.remove('show');
  }
}

Template:

<div
  (mouseenter)="enter()"
  (mousemove)="move($event)"
  (mouseleave)="leave()"
  class="place-welcome"
>
  <h2>This is a Panel</h2>
  <p>Hello my darling</p>
</div>

<div id="first">asdasdasdasd</div>

Stylesheet:

#first {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.place-welcome {
  width: 100%;
  height: 300px;
  background: red;
}

.show {
  opacity: 1 !important;
}

View on StackBlitz

Related