Skip to content

Commit

Permalink
Deploying to gh-pages from @ 84dd21b 🚀
Browse files Browse the repository at this point in the history
  • Loading branch information
OssamaRafique committed Nov 15, 2023
1 parent 9d5b50f commit 9565b32
Show file tree
Hide file tree
Showing 17 changed files with 2,586 additions and 272 deletions.
6 changes: 3 additions & 3 deletions docs/BaseGL.BaseGL.html

Large diffs are not rendered by default.

319 changes: 283 additions & 36 deletions docs/BaseGL.html

Large diffs are not rendered by default.

77 changes: 66 additions & 11 deletions docs/BaseGL.js.html

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/DotplotGL.DotplotGL.html

Large diffs are not rendered by default.

330 changes: 291 additions & 39 deletions docs/DotplotGL.html

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions docs/DotplotGL.js.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/RectplotGL.RectplotGL.html

Large diffs are not rendered by default.

316 changes: 284 additions & 32 deletions docs/RectplotGL.html

Large diffs are not rendered by default.

27 changes: 14 additions & 13 deletions docs/RectplotGL.js.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/TickplotGL.TickplotGL.html

Large diffs are not rendered by default.

316 changes: 284 additions & 32 deletions docs/TickplotGL.html

Large diffs are not rendered by default.

11 changes: 3 additions & 8 deletions docs/TickplotGL.js.html

Large diffs are not rendered by default.

700 changes: 700 additions & 0 deletions docs/global.html

Large diffs are not rendered by default.

31 changes: 28 additions & 3 deletions docs/index.html

Large diffs are not rendered by default.

257 changes: 257 additions & 0 deletions docs/utils.js.html

Large diffs are not rendered by default.

216 changes: 177 additions & 39 deletions ehgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,45 @@ const DEFAULT_SIZE_LEGEND_CIRCLE_TEXT_GAP = 10;
const DEFAULT_MIN_RADIUS_FOR_DOTPLOT = 3;
const DEFAULT_MARGIN_BETWEEN_DOTS = 2;

const DEFAULT_MARGINS = {
top: "25px",
bottom: "50px",
left: "50px",
right: "10px",
};

/**
* Check if a given variable is an object and not an array.
*
* @param {any} object - The variable to check.
* @returns {boolean} - Returns true if the variable is an object, and not an array.
*/
function isObject(object) {
return typeof object === "object" && Array.isArray(object) === false;
}

/**
* Get the minimum and maximum values from an array.
*
* @param {Array<number>} arr - An array of numbers.
* @returns {Array<number>} - An array containing the minimum and maximum values, in that order.
*/
const getMinMax = (arr) => {
var max = -Number.MAX_VALUE,
min = Number.MAX_VALUE;
arr.forEach(function (x) {
if (max < x) {
max = x;
}
if (min > x) {
min = x;
}
if (max < x) max = x;
if (min > x) min = x;
});
return [min, max];
};

/**
* Parses an object of margins and returns an object with top, bottom, left, and right margins as integers.
*
* @param {Object} margins - An object with potential margin properties.
* @returns {Object} - An object with top, bottom, left, and right margins as integers.
*/
const parseMargins = (margins) => {
const parsedMargins = {
top: 0,
Expand All @@ -73,6 +94,13 @@ const parseMargins = (margins) => {
return parsedMargins;
};

/**
* Measure the width of a text string for a given font size using SVG.
*
* @param {string} text - The text to measure.
* @param {string} fontSize - The font size to use for the measurement, e.g., '16px'.
* @returns {number} - The width of the text in pixels.
*/
const getTextWidth = (text, fontSize = "16px") => {
// Create a temporary SVG to measure the text width
const svg = d3Selection.select("body").append("svg");
Expand All @@ -82,6 +110,14 @@ const getTextWidth = (text, fontSize = "16px") => {
return width;
};

/**
* Create a tooltip on a specified container at the given position.
*
* @param {HTMLElement} container - The container element.
* @param {string} text - The text for the tooltip.
* @param {number} posX - The x-coordinate for the tooltip.
* @param {number} posY - The y-coordinate for the tooltip.
*/
const createTooltip = (container, text, posX, posY) => {
let tooltip = d3Selection.select(container)
.append("div")
Expand All @@ -101,6 +137,11 @@ const createTooltip = (container, text, posX, posY) => {
.style("top", posY - 10 + "px");
};

/**
* Remove a tooltip from the specified container.
*
* @param {HTMLElement} container - The container from which to remove the tooltip.
*/
const removeTooltip = (container) => {
const tooltip = d3Selection.select(container).select(`#${TOOLTIP_IDENTIFIER}`);

Expand Down Expand Up @@ -130,6 +171,52 @@ const getScaledRadiusForDotplot = (
);
};

/**
* A function to map over both regular JavaScript arrays and typed arrays.
*
* @param {Array|TypedArray} array - The input array or typed array.
* @param {Function} callback - A function that produces an element of the new array,
* taking three arguments:
* currentValue - The current element being processed in the array.
* index - The index of the current element being processed in the array.
* array - The array map was called upon.
* @returns {Array|TypedArray} - A new array or typed array with each element being the result
* of the callback function.
* @throws {Error} - Throws an error if the input is neither a regular array nor a typed array.
*/
const mapArrayOrTypedArray = (array, callback) => {
// Check if the input is a regular JavaScript array.
if (Array.isArray(array)) {
return array.map(callback);
}
// Check if the input is a typed array.
else if (
array instanceof Int8Array ||
array instanceof Uint8Array ||
array instanceof Uint8ClampedArray ||
array instanceof Int16Array ||
array instanceof Uint16Array ||
array instanceof Int32Array ||
array instanceof Uint32Array ||
array instanceof Float32Array ||
array instanceof Float64Array
) {
// Create a new typed array of the same type and size as the input.
let result = new array.constructor(array.length);

// Use forEach to emulate the map functionality for typed arrays.
array.forEach((value, index) => {
result[index] = callback(value, index);
});

return result;
}
// Handle the case where the input is neither a regular array nor a typed array.
else {
throw new Error("Input is neither a normal array nor a typed array.");
}
};

/**
* Base class for all matrix like layout plots.
* This class is not to be used directly.
Expand Down Expand Up @@ -180,8 +267,14 @@ class BaseGL {
ygap: 0.3,
};

this.margins = DEFAULT_MARGINS;

//Default Data for labelOptions
this.labelOptions = {
rowLabelsSvgXOffset: -1.05,
rowLabelsSvgYOffset: -1.02,
columnLabelsSvgXOffset: -1.02,
columnLabelsSvgYOffset: 1.05,
rowLabelMaxCharacters: DEFAULT_ROW_MAX_LABEL_LENGTH_ALLOWED,
columnLabelMaxCharacters: DEFAULT_COLUMN_MAX_LABEL_LENGTH_ALLOWED,
rowLabelSlintAngle: DEFAULT_ROW_LABEL_SLINT_ANGLE,
Expand Down Expand Up @@ -288,6 +381,10 @@ class BaseGL {

_generateSpecForLabels(spec) {
const {
rowLabelsSvgXOffset,
rowLabelsSvgYOffset,
columnLabelsSvgXOffset,
columnLabelsSvgYOffset,
rowLabelMaxCharacters,
columnLabelMaxCharacters,
rowLabelSlintAngle,
Expand Down Expand Up @@ -317,8 +414,8 @@ class BaseGL {

maxWidth = Math.max(maxWidth, truncatedLabelWidth);
labels.push({
x: -1.02 + (2 * ilx + 1) / xlabels_len,
y: 1.05,
x: columnLabelsSvgXOffset + (2 * ilx + 1) / xlabels_len,
y: columnLabelsSvgYOffset,
type: "row",
index: ilx,
text: truncatedLabel,
Expand Down Expand Up @@ -351,8 +448,8 @@ class BaseGL {
);
maxWidth = Math.max(maxWidth, truncatedLabelWidth);
labels.push({
x: -1.05,
y: -1.02 + (2 * ily + 1) / ylabels_len,
x: rowLabelsSvgXOffset,
y: rowLabelsSvgYOffset + (2 * ily + 1) / ylabels_len,
type: "column",
index: ily,
text: truncatedLabel,
Expand All @@ -374,7 +471,7 @@ class BaseGL {
...spec["margins"],
top: `${topMarginToAccountForLabels}px`,
left: `${leftMarginToAccountForLabels}px`,
right: "20px",
right: `${GROUPING_LEGEND_SIZE_IN_PX}px`,
};
}

Expand Down Expand Up @@ -603,6 +700,10 @@ class BaseGL {
* @memberof BaseGL
* @example
* this.labelOptions = {
* rowLabelsSvgXOffset: 0,
* rowLabelsSvgYOffset: 0,
* columnLabelsSvgXOffset: 0,
* columnLabelsSvgYOffset: 0,
* rowLabelMaxCharacters: 10,
* columnLabelMaxCharacters: 10,
* rowLabelSlintAngle: 0,
Expand All @@ -612,8 +713,12 @@ class BaseGL {
* }
* @example
* this.setLabelOptions({
* rowLabelsSvgXOffset: 0,
* rowLabelsSvgYOffset: 0,
* columnLabelsSvgXOffset: 0,
* columnLabelsSvgYOffset: 0,
* rowLabelMaxCharacters: 10,
* columnLabelMaxCharacters: 10,
* columnLabelMaxCharacters: 10,
* rowLabelSlintAngle: 0,
* columnLabelSlintAngle: 0,
* rowLabelFontSize: "7px",
Expand All @@ -627,6 +732,30 @@ class BaseGL {
};
}

/**
* Set the margins for the visualization.
* all properties are optional, if not provided, the default values will be used.
* @param {object} margins, an object containing the margins
* @param {number} margins.top, top margin
* @param {number} margins.bottom, bottom margin
* @param {number} margins.left, left margin
* @param {number} margins.right, right margin
* @memberof BaseGL
* @example
* this.setMargins({
* top: '10px',
* bottom: '10px',
* left: '10px',
* right: '10px',
* })
**/
setMargins(margins) {
this.margins = {
...this.margins,
...margins,
};
}

/**
* resize the plot, without having to send the data to the GPU.
*
Expand Down Expand Up @@ -1128,22 +1257,34 @@ class BaseGL {
* @param {string} orientation - The orientation of the grouping labels
* @returns {void}
**/
renderGroupingLabels(parentElement, groupingRowData, orientation) {
renderGroupingLabels(parentElement, groupingData, orientation) {
// Filter out duplicate labels in the grouping data
groupingData = groupingData.reduce(
(acc, obj) => {
if (!acc.seen[obj.label]) {
acc.seen[obj.label] = true;
acc.result.push(obj);
}
return acc;
},
{ seen: {}, result: [] }
).result;

const parent = d3Selection.select(parentElement);
const svg = parent.append("svg");

svg.attr("width", "100%").style("overflow", "inherit");
if (orientation === "horizontal") {
svg.attr("height", 25);
} else {
svg.attr("height", groupingRowData.length * 25);
svg.attr("height", groupingData.length * 25);
}

const labelHeight = 25;
let xOffset = 0;
let yOffset = 0;

groupingRowData.forEach((data) => {
groupingData.forEach((data) => {
const group = svg.append("g");

group
Expand Down Expand Up @@ -1463,16 +1604,17 @@ class DotplotGL extends BaseGL {
const [, maxY] = getMinMax(this.input.y);
let xlen = maxX + 1,
ylen = maxY + 1;
spec_inputs.x = this.input.x.map((e, i) => -1 + (2 * e + 1) / xlen);
spec_inputs.y = this.input.y.map((e, i) => -1 + (2 * e + 1) / ylen);
spec_inputs.x = mapArrayOrTypedArray(
this.input.x,
(e, i) => -1 + (2 * e + 1) / xlen
);
spec_inputs.y = mapArrayOrTypedArray(
this.input.y,
(e, i) => -1 + (2 * e + 1) / ylen
);

let spec = {
margins: {
top: "25px",
bottom: "50px",
left: "50px",
right: "10px",
},
margins: this.margins,
defaultData: {
x: spec_inputs.x,
y: spec_inputs.y,
Expand Down Expand Up @@ -1969,22 +2111,23 @@ class RectplotGL extends BaseGL {
};

let spec_inputs = {};
spec_inputs.x = this.input.x.map((e, i) => String(e));
spec_inputs.y = this.input.y.map((e, i) => String(e));
spec_inputs.x = mapArrayOrTypedArray(this.input.x, (e, i) => String(e));
spec_inputs.y = mapArrayOrTypedArray(this.input.y, (e, i) => String(e));

let default_width = 198 / (getMinMax(this.input.x)[1] + 1);
let default_height = 198 / (getMinMax(this.input.y)[1] + 1);

spec_inputs.width = this.input.x.map((e, i) => default_width - xGaps(i));
spec_inputs.height = this.input.y.map((e, i) => default_height - yGaps(i));
spec_inputs.width = mapArrayOrTypedArray(
this.input.x,
(e, i) => default_width - xGaps(i)
);
spec_inputs.height = mapArrayOrTypedArray(
this.input.y,
(e, i) => default_height - yGaps(i)
);

let spec = {
margins: {
top: "25px",
bottom: "50px",
left: "50px",
right: "10px",
},
margins: this.margins,
defaultData: {
x: spec_inputs.x,
y: spec_inputs.y,
Expand Down Expand Up @@ -2100,12 +2243,7 @@ class TickplotGL extends BaseGL {
}

let spec = {
margins: {
top: "25px",
bottom: "50px",
left: "50px",
right: "10px",
},
margins: this.margins,
defaultData: {
x: this.input.x,
y: this.input.y,
Expand Down
Loading

0 comments on commit 9565b32

Please sign in to comment.