/** A ContainerBlock is a container for other blocks (including other ContainerBlocks). */
class ContainerBlock {
/**
* Create a container block.
* @param {Object} options - Configuration options.
* @author Lawrence Fyfe
*/
constructor(options) {
this.blockType = "container";
this.direction = options?.direction ?? "column";
this.blockArray = [];
this.parentElement;
}
/**
* Add the specified block to this block.
* @param {block} block - The block to add.
*/
addBlock(block) {
this.blockArray.push(block);
}
/**
* Initialize this block by attaching it to the specified parent element.
* @param {element} parentElement - The parent element.
*/
initialize(parentElement) {
this.parentElement = parentElement instanceof d3.selection ? parentElement : d3.select(parentElement);
}
/**
* Draw this block.
*/
draw() {
if (this.parentElement !== undefined) {
this.containerBlockDiv = this.parentElement.append("div")
.attr("class", "containerBlockDiv")
.style("display", "flex")
.style("flex-direction", this.direction);
for (let i = 0; i < this.blockArray.length; i++) {
this.blockArray[i].parentElement = this.containerBlockDiv;
this.blockArray[i].draw();
}
}
}
/**
* Erase this block.
*/
erase() {
if (this.containerBlockDiv !== undefined) {
this.containerBlockDiv.selectAll("*").remove();
}
}
}
/** An PanelBlock is a container for panels. */
class PanelBlock {
/**
* Create a panel block.
* @author Lawrence Fyfe
*/
constructor() {
this.blockType = "panel";
this.paneArray = [];
this.singleCurrentPane;
this.parentElement;
this.initialized = false;
}
/**
* Add the specified pane to this block.
* @param {pane} pane - The pane to add.
*/
addPane(pane) {
this.paneArray.push(pane);
}
/**
* Set the specified pane to be the single current pane for this block. This method is used when there are multiple layered panel panes
* in a block and only one panel can be shown at a time.
* @param {pane} pane - The pane to set as the single current pane.
*/
setSingleCurrentPane(pane) {
if (this.paneArray.find((element) => element === pane) !== undefined) {
this.singleCurrentPane = pane;
}
}
/**
* Initialize this block by attaching it to the specified parent element.
* @param {element} parentElement - The parent element.
*/
initialize(parentElement) {
this.parentElement = parentElement instanceof d3.selection ? parentElement : d3.select(parentElement);
this.panelBlockDiv = this.parentElement.append("div")
.attr("class", "panelBlockDiv");
this.initialized = true;
}
/**
* Draw this block.
*/
draw() {
if (this.initialized) {
this.erase();
for (let i = 0; i < this.paneArray.length; i++) {
this.paneArray[i].initializePanel(this.panelBlockDiv);
}
if (this.initialized) {
if (this.singleCurrentPane !== undefined) {
this.singleCurrentPane.drawPanel();
}
else {
for (let i = 0; i < this.paneArray.length; i++) {
this.paneArray[i].drawPanel();
}
}
}
}
}
/**
* Erase this block.
*/
erase() {
for (let i = 0; i < this.paneArray.length; i++) {
this.paneArray[i].panelOn = false;
}
if (this.panelBlockDiv !== undefined) {
this.panelBlockDiv.selectAll("*").remove();
}
}
}
/** An SVG image block contains an SVG image. */
class SVGImageBlock {
/**
* Create a block for an SVG image.
* @param {string} file - The SVG file name String.
* @author Lawrence Fyfe
*/
constructor(file) {
this.blockType = "svgImage";
this.file = file;
this.svg;
this.svgWidth;
this.svgHeight;
this.parentElement;
this.width;
this.height;
this.initialized = false;
this.fileIsReady = d3.svg(this.file).then((svg) => {
this.svg = svg.documentElement;
this.svgWidth = svg.documentElement.getAttribute("width");
this.svgHeight = svg.documentElement.getAttribute("height");
});
}
/**
* Determines whether the SVG file specified for this block as been fetched.
*/
async isReady() {
await this.fileIsReady;
}
/**
* Initialize this block with the specified parameters.
* @param {element} parentElement - The parent element.
* @param {number} width - The width to use for the SVG image.
* @param {number} height - The height to use for the SVG image.
*/
initialize(parentElement, width, height) {
this.parentElement = parentElement instanceof d3.selection ? parentElement : d3.select(parentElement);
this.width = width;
this.height = height;
this.svgImageBlockDiv = this.parentElement.append("div")
.attr("class", "svgImageBlockDiv");
this.initialized = true;
}
/**
* Draw this block.
*/
draw() {
if (this.initialized) {
this.fileIsReady.then(() => {
this.erase();
this.svgImageBlockDiv.append(() => this.svg)
.attr("class", "svgImage")
.attr("x", "0")
.attr("y", "0")
.attr("width", this.width)
.attr("height", this.height);
});
}
}
/**
* Erase this block.
*/
erase() {
if (this.svgImageBlockDiv !== undefined) {
this.svgImageBlockDiv.select("svg").remove();
}
}
}