lazy-widgets
Version:
Typescript retained mode GUI for the HTML canvas API
103 lines • 3.68 kB
JavaScript
import { LeaveEvent } from '../events/LeaveEvent.js';
import { PointerMoveEvent } from '../events/PointerMoveEvent.js';
import { PassthroughWidget } from './PassthroughWidget.js';
import { PropagationModel } from '../events/WidgetEvent.js';
import { TooltipController } from '../helpers/TooltipController.js';
const SENSITIVITY_RADIUS = 8;
const HOVER_TIME = 1000;
/**
* Wraps a widget and provides a tooltip. Automatically manages a given
* {@link TooltipContainer}, which will be used as the actual visual tooltip.
*
* Whenever this widget is hovered for a small amount of time without moving
* the pointer too much, a new layer will be created with the passed
* {@link TooltipContainer}, in the top-most {@link LayeredContainer}.
* Unhovering this wrapper will remove the layer.
*
* Has a tolerance for small movements, so that shaky pointers can still be used
* to detect hovering.
*
* @category Widget
*/
export class Tooltip extends PassthroughWidget {
constructor(child, tooltipWidget, properties) {
super(child, properties);
/**
* The timestamp for when the hovering started. 0 if not hovering. For
* internal use only.
*/
this._hoverStart = 0;
/**
* The pointer position for when the hovering started. For internal use
* only.
*/
this._hoverStartPos = [0, 0];
this.tooltipWidget = tooltipWidget;
this.controller = new TooltipController(this, tooltipWidget);
}
handleAttachment() {
super.handleAttachment();
this.controller.findTopLayeredContainer();
}
handleDetachment() {
this.controller.clearTopLayeredContainer();
super.handleDetachment();
}
handlePreLayoutUpdate() {
super.handlePreLayoutUpdate();
// show tooltip if hovered for long enough
if (this._hoverStart !== 0 && !this.controller.hasLayer && (Date.now() - this._hoverStart) >= HOVER_TIME) {
this.controller.addLayer(this._hoverStartPos);
}
}
handleEvent(event) {
if (event.propagation !== PropagationModel.Trickling) {
return super.handleEvent(event);
}
// check if this event should count as a hover/unhover
if (event.isa(PointerMoveEvent)) {
if (this._hoverStart === 0) {
this._hoverStart = Date.now();
this._hoverStartPos[0] = event.x;
this._hoverStartPos[1] = event.y;
}
else if (!this.controller.hasLayer) {
const xDiff = Math.abs(this._hoverStartPos[0] - event.x);
const yDiff = Math.abs(this._hoverStartPos[1] - event.y);
if (xDiff > SENSITIVITY_RADIUS || yDiff > SENSITIVITY_RADIUS) {
this._hoverStart = Date.now();
this._hoverStartPos[0] = event.x;
this._hoverStartPos[1] = event.y;
}
}
}
else if (event.isa(LeaveEvent)) {
this._hoverStart = 0;
this.controller.removeLayer();
}
// dispatch event to child
return this.child.dispatchEvent(event);
}
resolvePosition(x, y) {
super.resolvePosition(x, y);
this.controller.updateTooltipRect();
}
finalizeBounds() {
super.finalizeBounds();
this.controller.updateTooltipRect();
}
}
Tooltip.autoXML = {
name: 'tooltip',
inputConfig: [
{
mode: 'widget',
name: 'child'
},
{
mode: 'widget',
name: 'tooltip-widget'
}
]
};
//# sourceMappingURL=Tooltip.js.map