UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

167 lines (122 loc) 4.51 kB
import Rectangle from "../../core/geom/2d/Rectangle.js"; import { VisualTip } from "./VisualTip.js"; import Signal from "../../core/events/signal/Signal.js"; import ObservedBoolean from "../../core/model/ObservedBoolean.js"; import { DomSizeObserver } from "../util/DomSizeObserver.js"; import { SignalBinding } from "../../core/events/signal/SignalBinding.js"; import { MouseEvents } from "../../engine/input/devices/events/MouseEvents.js"; export class DomTooltipObserver { /** * * @param {View} view * @param {function} factory * @param {*} [factoryContext] */ constructor(view, factory, factoryContext) { /** * * @type {View} */ this.view = view; /** * * @type {Function} */ this.factory = factory; const tipTargetRectangle = new Rectangle(); /** * * @type {Rectangle} */ this.tipTargetRectangle = tipTargetRectangle; /** * * @type {VisualTip} */ this.tip = new VisualTip(tipTargetRectangle, factory, factoryContext); this.on = { entered: new Signal(), exited: new Signal() }; const isEntered = this.isEntered = new ObservedBoolean(false); const sizeObserver = new DomSizeObserver(); this.sizeObserver = sizeObserver; this.bindings = [ new SignalBinding(view.position.onChanged, this.__copyDimensions, this), new SignalBinding(view.size.onChanged, this.__copyDimensions, this), new SignalBinding(sizeObserver.dimensions.position.onChanged, this.__copyDimensionsFromBoundingRect, this), new SignalBinding(sizeObserver.dimensions.size.onChanged, this.__copyDimensionsFromBoundingRect, this) ]; this.handleMouseEnter = () => { isEntered.set(true); this.on.entered.send0(); sizeObserver.attach(view.el); sizeObserver.start(); } this.handleMouseLeave = () => { isEntered.set(false); sizeObserver.stop(); this.on.exited.send0(); } } __copyDimensionsFromBoundingRect() { const d = this.sizeObserver.dimensions; this.tipTargetRectangle.copy(d); }; __copyDimensions() { const view = this.view; const position = view.position; const scale = view.scale; const size = view.size; const r = this.tipTargetRectangle; r.position.set(position.x, position.y); r.size.set(size.x * scale.x, size.y * scale.y); } __handleViewLinked() { const view = this.view; const el = view.el; //ensure that the element can capture pointer events el.style.pointerEvents = "auto"; el.addEventListener(MouseEvents.Enter, this.handleMouseEnter); el.addEventListener(MouseEvents.Leave, this.handleMouseLeave); const bindings = this.bindings; const binding_count = bindings.length; for (let i = 0; i < binding_count; i++) { const b = bindings[i]; b.link(); } this.__copyDimensions(); } __handleViewUnlinked() { const view = this.view; const el = view.el; el.removeEventListener(MouseEvents.Enter, this.handleMouseEnter); el.removeEventListener(MouseEvents.Leave, this.handleMouseLeave); const bindings = this.bindings; const binding_count = bindings.length; for (let i = 0; i < binding_count; i++) { const b = bindings[i]; b.unlink(); } if (this.isEntered.getValue()) { //remove tip this.handleMouseLeave(); } }; link() { const view = this.view; if (view.isLinked) { this.__handleViewLinked(); } view.on.linked.add(this.__handleViewLinked, this); view.on.unlinked.add(this.__handleViewUnlinked, this); } unlink() { const view = this.view; if (view.isLinked) { this.__handleViewUnlinked(); } view.on.linked.remove(this.__handleViewLinked, this); view.on.unlinked.remove(this.__handleViewUnlinked, this); } }