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-l2wgqt?file=src/app/app.component.ts
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)">
<h2>This is a Panel</h2>
<p>Hello my darling</p>
</div>
<div id="first">asdasdasdasd</div>
CodePudding user response:
Instead of using mouseover
and mouseleave
, use:
mousenter
to detect when the mouse enters thediv
. This is where you display the tooltip.mousemove
to detect when the mouse is moved inside thediv
. This is where you position the tooltip.mouseleave
to detect when the mouse leaves thediv
. 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
tonone
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()"
>
<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
CodePudding user response:
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 onm ouseover