import { HTMLWidget, Text } from "@hpcc-js/common"; import "../src/Layered.css"; export type LayerPlacement = "default" | "top" | "right" | "bottom" | "left" | "center"; export class Layered extends HTMLWidget { protected _contentContainer; _widgetPlacements; _widgetRatios; constructor() { super(); this._tag = "div"; this._widgetPlacements = []; this._widgetRatios = []; } addLayer(widget, placement: LayerPlacement = "default", widthRatio: number = 1, heightRatio: number = 1) { const widgets = this.widgets(); widgets.push(widget ? widget : new Text().text("No widget defined for layer.")); this.widgets(widgets); this._widgetPlacements.push(placement); this._widgetRatios.push([widthRatio, heightRatio]); return this; } enter(domNode, element) { super.enter(domNode, element); this._contentContainer = element.append("div") .attr("class", "container") ; } update(domNode, element) { super.update(domNode, element); const context = this; element.style("padding", this.surfacePadding() + "px"); const content = this._contentContainer.selectAll(".content.id" + this.id()).data(this.widgets(), function (d) { return d.id(); }); content.enter().append("div") .attr("class", "content id" + this.id()) .each(function (widget, idx) { widget.target(this); }) .merge(content) .each(function (widget, idx) { const clientSize = { width: context.clientWidth(), height: context.clientHeight() }; const widgetSize = context.widgetSize(idx, clientSize); const widgetPosition = context.widgetPosition(idx, clientSize, widgetSize); this.style.top = widgetPosition.y + "px"; this.style.left = widgetPosition.x + "px"; widget .resize(widgetSize) .render() ; }) ; content.exit() .each(function (widget, idx) { widget .target(null) ; }) .remove() ; content.order(); } widgetSize(idx, clientSize) { if (this._widgetPlacements[idx] === "default") { return { width: clientSize.width * this._widgetRatios[idx][0], height: clientSize.height * this._widgetRatios[idx][1] }; } else { return { width: clientSize.width * this._widgetRatios[idx][0], height: clientSize.height * this._widgetRatios[idx][1] }; } } widgetPosition(idx, clientSize, widgetSize) { switch (this._widgetPlacements[idx]) { default: return { x: 0, y: 0 }; case "top": return { x: (clientSize.width / 2) - (widgetSize.width / 2), y: 0 }; case "bottom": return { x: (clientSize.width / 2) - (widgetSize.width / 2), y: clientSize.height - widgetSize.height }; case "left": return { x: 0, y: (clientSize.height / 2) - (widgetSize.height / 2) }; case "right": return { x: clientSize.width - widgetSize.width, y: (clientSize.height / 2) - (widgetSize.height / 2) }; case "center": return { x: (clientSize.width / 2) - (widgetSize.width / 2), y: (clientSize.height / 2) - (widgetSize.height / 2) }; } } } Layered.prototype._class += " layout_Layered"; export interface Layered { surfacePadding(): number; surfacePadding(_: number): this; widgets(): any; widgets(_: any): this; } Layered.prototype.publish("surfacePadding", 0, "number", "Padding"); Layered.prototype.publish("widgets", [], "widgetArray", "widgets", null, { tags: ["Private"] });