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:
mousenterto detect when the mouse enters thediv. This is where you display the tooltip.mousemoveto detect when the mouse is moved inside thediv. This is where you position the tooltip.mouseleaveto 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-eventstononefor 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
