import { THisHelper } from "./this.mjs";
export { ProtocolDatum };
/** Class representing a datum for a protocol */
class ProtocolDatum {
/**
*
* @param {number | number[]} value Datum value or array of X, Y pairs
* @param {string} name Datum name
* @param {?number} line_colour Line colour
* @param {?number} colour_above Colour to fill above datum
* @param {?number} colour_below Colour to fill below datum
* @param {?number} colour_left Colour to fill to the left of the datum
* @param {?number} colour_right Colour to fill to the right of the datum
* @example
* // Constant value datum
* let pd = new ProtocolDatum(10.0, "My Datum", Colour.GREEN, Colour.RED, Colour.GREEN);
*
* // Variable value datum
* let pd = new ProtocolDatum([0.0, 10.0, 0.5, 20.0, 1.0, 30.0],
* "My Datum",
* Colour.GREEN,
* Colour.RED,
* Colour.GREEN);
*/
constructor(value, name, line_colour, colour_above, colour_below, colour_left, colour_right) {
this.value = value;
this.name = name;
this.line_colour = line_colour;
this.colour_above = colour_above;
this.colour_below = colour_below;
this.colour_left = colour_left;
this.colour_right = colour_right;
}
/* Instance property getter and setters */
/**
* Datum value or array of X, Y pairs
* @type {number | number[]}
*/
get value() {
return this._value;
}
set value(new_value) {
if (typeof new_value != "number" && !(new_value instanceof Array)) {
throw new Error("value must be a number or an array of numbers");
}
this._value = new_value;
}
/**
* Datum name
* @type {string}
*/
get name() {
return this._name;
}
set name(new_name) {
if (typeof new_name != "string") {
throw new Error("name must be a string");
}
this._name = new_name;
}
/**
* Line colour
* @type {?number}
*/
get line_colour() {
return this._line_colour;
}
set line_colour(new_line_colour) {
if (typeof new_line_colour != "number") {
throw new Error("line_colour must be a number");
}
this._line_colour = new_line_colour;
}
/**
* Colour to fill above datum
* @type {?number}
*/
get colour_above() {
return this._colour_above;
}
set colour_above(new_colour_above) {
if (new_colour_above && typeof new_colour_above != "number") {
throw new Error("colour_above must be a number");
}
this._colour_above = new_colour_above;
}
/**
* Colour to fill below datum
* @type {?number}
*/
get colour_below() {
return this._colour_below;
}
set colour_below(new_colour_below) {
if (new_colour_below && typeof new_colour_below != "number") {
throw new Error("colour_below must be a number");
}
this._colour_below = new_colour_below;
}
/**
* Colour to fill to left of datum
* @type {?number}
*/
get colour_left() {
return this._colour_left;
}
set colour_left(new_colour_left) {
if (new_colour_left && typeof new_colour_left != "number") {
throw new Error("colour_left must be a number");
}
this._colour_left = new_colour_left;
}
/**
* Colour to fill to right of datum
* @type {?number}
*/
get colour_right() {
return this._colour_right;
}
set colour_right(new_colour_right) {
if (new_colour_right && typeof new_colour_right != "number") {
throw new Error("colour_right must be a number");
}
this._colour_right = new_colour_right;
}
/* Instance methods */
/**
* Returns the minimum X value of the datum
* If it's a constant value datum, returns Number.MAX_VALUE
* @returns {number}
* @example
* let min_x = pd.MinX();
*/
MinX() {
let min_x = Number.MAX_VALUE;
if (this.value instanceof Array) {
for (let i = 0; i < this.value.length; i += 2) {
if (this.value[i] < min_x) min_x = this.value[i];
}
}
return min_x;
}
/**
* Returns the maximum X value of the datum
* If it's a constant value datum, returns -Numer.MAX_VALUE
* @returns {number}
* @example
* let max_x = pd.MaxX();
*/
MaxX() {
let max_x = -Number.MAX_VALUE;
if (this.value instanceof Array) {
for (let i = 0; i < this.value.length; i += 2) {
if (this.value[i] > max_x) max_x = this.value[i];
}
}
return max_x;
}
/**
* Returns the minimum Y value of the datum
* @returns {number}
* @example
* let min_y = pd.MinY();
*/
MinY() {
let min_y = Number.MAX_VALUE;
if (this.value instanceof Array) {
for (let i = 1; i < this.value.length; i += 2) {
if (this.value[i] < min_y) min_y = this.value[i];
}
} else {
min_y = this.value;
}
return min_y;
}
/**
* Returns the maximum Y value of the datum
* @returns {number}
* @example
* let max_y = pd.MaxY();
*/
MaxY() {
let max_y = -Number.MAX_VALUE;
if (this.value instanceof Array) {
for (let i = 1; i < this.value.length; i += 2) {
if (this.value[i] > max_y) max_y = this.value[i];
}
} else {
max_y = this.value;
}
return max_y;
}
/**
* Extends the last point on the datum to the specified X value
* @param {number} x X value to extend the datum to
*/
ExtendLastYValueToX(x) {
if (this.value instanceof Array) {
if (x <= this.value[this.value.length - 2]) return;
this.value.push(x);
this.value.push(this.value[this.value.length - 2]);
}
}
/**
* Plot a datum
* @param {number} [graph] Index of graph to plot on. If not specified, it's plotted on all graphs
* @example
* pd.Plot();
*/
Plot(graph) {
/* Delete a datum if it already exists, storing the graphs it is
* currently on so we can add it back later */
let on_graphs = [];
if (Datum.Exists(this.name)) {
let d = Datum.GetFromAcronym(this.name);
for (let i = 1; i < THisHelper.MAX_GRAPHS; i++) {
if (d.IsOnGraph(i)) {
on_graphs.push(i);
}
}
Datum.Delete(this.name);
}
/* Create a new datum */
/** @type {Datum} */
let datum;
if (this.value instanceof Array) {
datum = new Datum(this.name, Datum.POINTS, this.value);
} else {
datum = new Datum(this.name, Datum.CONSTANT_Y, this.value);
}
if (this.line_colour) datum.line_colour = this.line_colour;
if (this.colour_below) datum.fill_colour_below = this.colour_below;
if (this.colour_above) datum.fill_colour_above = this.colour_above;
if (this.colour_left) {
datum.fill_type = Datum.FILL_RIGHT_LEFT;
datum.fill_colour_left = this.colour_left;
}
if (this.colour_right) {
datum.fill_type = Datum.FILL_RIGHT_LEFT;
datum.fill_colour_right = this.colour_right;
}
/* If the graph is specified, plot the datum on that graph, otherwise plot it on all graphs */
if (graph) {
datum.RemoveFromGraph();
datum.AddToGraph(graph);
} else {
datum.AddToGraph();
}
/* Add it to the graphs it was originally on */
for (let id of on_graphs) {
datum.AddToGraph(id);
}
/* Update the graphs in T/HIS */
Plot();
}
}