cheetah-grid
Version:
Cheetah Grid is a high performance grid engine that works on canvas
151 lines (138 loc) • 4.53 kB
text/typescript
import { EventHandler } from "../../internal/EventHandler";
import type { ListGridAPI } from "../../ts-types";
import { createElement } from "../../internal/dom";
const CLASSNAME = "cheetah-grid__tooltip-element";
const CONTENT_CLASSNAME = `${CLASSNAME}__content`;
const HIDDEN_CLASSNAME = `${CLASSNAME}--hidden`;
const SHOWN_CLASSNAME = `${CLASSNAME}--shown`;
function createTooltipDomElement(): HTMLElement {
require("@/tooltip/internal/TooltipElement.css");
const rootElement = createElement("div", {
classList: [CLASSNAME, HIDDEN_CLASSNAME],
});
const messageElement = createElement("pre", {
classList: [CONTENT_CLASSNAME],
});
rootElement.appendChild(messageElement);
return rootElement;
}
export class TooltipElement<T> {
private _handler: EventHandler;
private _rootElement: HTMLElement;
private _messageElement: HTMLElement;
constructor() {
this._handler = new EventHandler();
const rootElement = (this._rootElement = createTooltipDomElement());
this._messageElement = rootElement.querySelector(
`.${CONTENT_CLASSNAME}`
) as HTMLElement;
}
dispose(): void {
this.detach();
const rootElement = this._rootElement;
if (rootElement.parentElement) {
rootElement.parentElement.removeChild(rootElement);
}
this._handler.dispose();
// @ts-expect-error -- ignore
delete this._rootElement;
// @ts-expect-error -- ignore
delete this._messageElement;
}
attach(
grid: ListGridAPI<T>,
col: number,
row: number,
content: string
): void {
const rootElement = this._rootElement;
const messageElement = this._messageElement;
rootElement.classList.remove(SHOWN_CLASSNAME);
rootElement.classList.add(HIDDEN_CLASSNAME);
if (this._attachCell(grid, col, row)) {
rootElement.classList.add(SHOWN_CLASSNAME);
rootElement.classList.remove(HIDDEN_CLASSNAME);
messageElement.textContent = content;
} else {
this._detach();
}
}
move(grid: ListGridAPI<T>, col: number, row: number): void {
const rootElement = this._rootElement;
if (this._attachCell(grid, col, row)) {
rootElement.classList.add(SHOWN_CLASSNAME);
rootElement.classList.remove(HIDDEN_CLASSNAME);
} else {
this._detach();
}
}
detach(): void {
this._detach();
}
_detach(): void {
const rootElement = this._rootElement;
if (rootElement.parentElement) {
// rootElement.parentElement.removeChild(rootElement);
rootElement.classList.remove(SHOWN_CLASSNAME);
rootElement.classList.add(HIDDEN_CLASSNAME);
}
}
_attachCell(grid: ListGridAPI<T>, col: number, row: number): boolean {
const rootElement = this._rootElement;
const { element, rect } = grid.getAttachCellsArea(
grid.getCellRange(col, row)
);
const { bottom: top, left, width } = rect;
const { frozenRowCount, frozenColCount } = grid;
if (row >= frozenRowCount && frozenRowCount > 0) {
const { rect: frozenRect } = grid.getAttachCellsArea(
grid.getCellRange(col, frozenRowCount - 1)
);
if (top < frozenRect.bottom) {
return false; //範囲外
}
} else {
if (top < 0) {
return false; //範囲外
}
}
if (col >= frozenColCount && frozenColCount > 0) {
const { rect: frozenRect } = grid.getAttachCellsArea(
grid.getCellRange(frozenColCount - 1, row)
);
if (left < frozenRect.right) {
return false; //範囲外
}
} else {
if (left < 0) {
return false; //範囲外
}
}
const {
height: offsetHeight,
width: offsetWidth,
left: elementLeft,
right: elementRight,
} = element.getBoundingClientRect();
if (offsetHeight < top) {
return false; //範囲外
}
if (offsetWidth < left) {
return false; //範囲外
}
const cellCenter = left + width / 2;
rootElement.style.top = `${top.toFixed()}px`;
rootElement.style.left = `${cellCenter.toFixed()}px`;
rootElement.style.minWidth = `${width.toFixed()}px`;
const maxWidthForLeft = (elementLeft + cellCenter) * 2;
const winWidth = window.innerWidth;
const maxWidthForRight =
(offsetWidth - cellCenter + (winWidth - elementRight)) * 2;
const maxWidth = Math.min(maxWidthForLeft, maxWidthForRight);
rootElement.style.maxWidth = `${maxWidth.toFixed()}px`;
if (rootElement.parentElement !== element) {
element.appendChild(rootElement);
}
return true;
}
}