From 15820f2282e156f6bbe3bb6a853eb896f4cee91b Mon Sep 17 00:00:00 2001 From: Benoit Simard Date: Mon, 18 Sep 2023 14:42:54 +0200 Subject: [PATCH] Typing graph on SIgma class --- examples/custom-rendering/node.border.ts | 6 ++- examples/use-reducers/index.ts | 13 ++++- examples/webpack.config.js | 2 +- src/rendering/canvas/edge-label.ts | 4 +- src/rendering/canvas/hover.ts | 4 +- src/rendering/canvas/label.ts | 4 +- src/rendering/webgl/programs/common/edge.ts | 20 +++++--- src/rendering/webgl/programs/common/node.ts | 20 +++++--- .../webgl/programs/common/program.ts | 15 ++++-- .../webgl/programs/edge.arrowHead.ts | 6 ++- src/rendering/webgl/programs/edge.line.ts | 6 ++- .../webgl/programs/edge.rectangle.ts | 6 ++- src/rendering/webgl/programs/edge.triangle.ts | 6 ++- src/rendering/webgl/programs/node.circle.ts | 6 ++- src/rendering/webgl/programs/node.image.ts | 6 ++- src/rendering/webgl/programs/node.point.ts | 6 ++- src/settings.ts | 23 +++++---- src/sigma.ts | 48 ++++++++++++------- 18 files changed, 142 insertions(+), 59 deletions(-) diff --git a/examples/custom-rendering/node.border.ts b/examples/custom-rendering/node.border.ts index 338dbe68b..f820c01ec 100644 --- a/examples/custom-rendering/node.border.ts +++ b/examples/custom-rendering/node.border.ts @@ -12,6 +12,7 @@ * every GPU. * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, RenderParams } from "sigma/types"; import { floatColor } from "sigma/utils"; import { NodeProgram } from "sigma/rendering/webgl/programs/common/node"; @@ -22,7 +23,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_sizeRatio", "u_pixelRatio", "u_matrix"] as const; -export default class NodeBorderProgram extends NodeProgram { +export default class NodeBorderProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends NodeProgram { getDefinition() { return { VERTICES: 1, diff --git a/examples/use-reducers/index.ts b/examples/use-reducers/index.ts index 20df61bb4..69453607d 100644 --- a/examples/use-reducers/index.ts +++ b/examples/use-reducers/index.ts @@ -9,6 +9,16 @@ import { Coordinates, EdgeDisplayData, NodeDisplayData } from "sigma/types"; import Graph from "graphology"; import data from "./data.json"; +interface NodeData { + x: number; + y: number; + size: number; + label: string; + color: string; +} +interface EdgeData { + size: number; +} // Retrieve some useful DOM elements: const container = document.getElementById("sigma-container") as HTMLElement; @@ -16,7 +26,7 @@ const searchInput = document.getElementById("search-input") as HTMLInputElement; const searchSuggestions = document.getElementById("suggestions") as HTMLDataListElement; // Instantiate sigma: -const graph = new Graph(); +const graph = new Graph(); graph.import(data); const renderer = new Sigma(graph, container); @@ -116,7 +126,6 @@ renderer.on("leaveNode", () => { // 3. If there is a hovered node, all non-neighbor nodes are greyed renderer.setSetting("nodeReducer", (node, data) => { const res: Partial = { ...data }; - if (state.hoveredNeighbors && !state.hoveredNeighbors.has(node) && state.hoveredNode !== node) { res.label = ""; res.color = "#f6f6f6"; diff --git a/examples/webpack.config.js b/examples/webpack.config.js index e1b98015f..599a4be21 100644 --- a/examples/webpack.config.js +++ b/examples/webpack.config.js @@ -20,7 +20,7 @@ module.exports = { __dirname, "../src/rendering/webgl/programs/common/node.ts", ), - sigma: path.resolve(__dirname, "../src/index.ts"), + sigma: path.resolve(__dirname, "../src"), }, }, module: { diff --git a/src/rendering/canvas/edge-label.ts b/src/rendering/canvas/edge-label.ts index b8e5887a5..6392d1b69 100644 --- a/src/rendering/canvas/edge-label.ts +++ b/src/rendering/canvas/edge-label.ts @@ -8,12 +8,12 @@ import { Settings } from "../../settings"; import { EdgeDisplayData, NodeDisplayData, PartialButFor } from "../../types"; -export default function drawEdgeLabel( +export default function drawEdgeLabel( context: CanvasRenderingContext2D, edgeData: PartialButFor, sourceData: PartialButFor, targetData: PartialButFor, - settings: Settings, + settings: Settings, ): void { const size = settings.edgeLabelSize, font = settings.edgeLabelFont, diff --git a/src/rendering/canvas/hover.ts b/src/rendering/canvas/hover.ts index e59e0a4e8..d103093ab 100644 --- a/src/rendering/canvas/hover.ts +++ b/src/rendering/canvas/hover.ts @@ -16,10 +16,10 @@ import drawLabel from "./label"; * - if the label box is bigger than node size => display a label box that contains the node with a shadow * - else node with shadow and the label box */ -export default function drawHover( +export default function drawHover( context: CanvasRenderingContext2D, data: PartialButFor, - settings: Settings, + settings: Settings, ): void { const size = settings.labelSize, font = settings.labelFont, diff --git a/src/rendering/canvas/label.ts b/src/rendering/canvas/label.ts index 7e0c75f5e..6afb76daf 100644 --- a/src/rendering/canvas/label.ts +++ b/src/rendering/canvas/label.ts @@ -8,10 +8,10 @@ import { Settings } from "../../settings"; import { NodeDisplayData, PartialButFor } from "../../types"; -export default function drawLabel( +export default function drawLabel( context: CanvasRenderingContext2D, data: PartialButFor, - settings: Settings, + settings: Settings, ): void { if (!data.label) return; diff --git a/src/rendering/webgl/programs/common/edge.ts b/src/rendering/webgl/programs/common/edge.ts index 8c2baafce..faa53591a 100644 --- a/src/rendering/webgl/programs/common/edge.ts +++ b/src/rendering/webgl/programs/common/edge.ts @@ -4,11 +4,15 @@ * * @module */ +import { Attributes } from "graphology-types"; import Sigma from "../../../../sigma"; import { AbstractProgram, Program } from "./program"; import { NodeDisplayData, EdgeDisplayData, RenderParams } from "../../../../types"; -export abstract class AbstractEdgeProgram extends AbstractProgram { +export abstract class AbstractEdgeProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends AbstractProgram { abstract process( offset: number, sourceData: NodeDisplayData, @@ -17,9 +21,13 @@ export abstract class AbstractEdgeProgram extends AbstractProgram { ): void; } -export abstract class EdgeProgram - extends Program - implements AbstractEdgeProgram +export abstract class EdgeProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, + Uniform extends string = string, + > + extends Program + implements AbstractEdgeProgram { process(offset: number, sourceData: NodeDisplayData, targetData: NodeDisplayData, data: EdgeDisplayData): void { let i = offset * this.STRIDE; @@ -41,8 +49,8 @@ export abstract class EdgeProgram ): void; } -export interface EdgeProgramConstructor { - new (gl: WebGLRenderingContext, renderer: Sigma): AbstractEdgeProgram; +export interface EdgeProgramConstructor { + new (gl: WebGLRenderingContext, renderer: Sigma): AbstractEdgeProgram; } /** diff --git a/src/rendering/webgl/programs/common/node.ts b/src/rendering/webgl/programs/common/node.ts index c85219dc7..86fd3dfbb 100644 --- a/src/rendering/webgl/programs/common/node.ts +++ b/src/rendering/webgl/programs/common/node.ts @@ -4,17 +4,25 @@ * * @module */ +import { Attributes } from "graphology-types"; import Sigma from "../../../../sigma"; import { AbstractProgram, Program } from "./program"; import { NodeDisplayData, RenderParams } from "../../../../types"; -export abstract class AbstractNodeProgram extends AbstractProgram { +export abstract class AbstractNodeProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends AbstractProgram { abstract process(offset: number, data: NodeDisplayData): void; } -export abstract class NodeProgram - extends Program - implements AbstractNodeProgram +export abstract class NodeProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, + Uniform extends string = string, + > + extends Program + implements AbstractNodeProgram { process(offset: number, data: NodeDisplayData): void { let i = offset * this.STRIDE; @@ -31,8 +39,8 @@ export abstract class NodeProgram abstract processVisibleItem(i: number, data: NodeDisplayData): void; } -export interface NodeProgramConstructor { - new (gl: WebGLRenderingContext, renderer: Sigma): AbstractNodeProgram; +export interface NodeProgramConstructor { + new (gl: WebGLRenderingContext, renderer: Sigma): AbstractNodeProgram; } /** diff --git a/src/rendering/webgl/programs/common/program.ts b/src/rendering/webgl/programs/common/program.ts index ae8d1d7d1..c506ad8a3 100644 --- a/src/rendering/webgl/programs/common/program.ts +++ b/src/rendering/webgl/programs/common/program.ts @@ -5,12 +5,13 @@ * Class representing a single WebGL program used by sigma's WebGL renderer. * @module */ +import { Attributes } from "graphology-types"; import type Sigma from "../../../../sigma"; import type { RenderParams } from "../../../../types"; import { canUse32BitsIndices } from "../../../../utils"; import { loadVertexShader, loadFragmentShader, loadProgram } from "../../shaders/utils"; -const SIZE_FACTOR_PER_ATTRIBUTE_TYPE = { +const SIZE_FACTOR_PER_ATTRIBUTE_TYPE: Record = { [WebGL2RenderingContext.BOOL]: 1, [WebGL2RenderingContext.BYTE]: 1, [WebGL2RenderingContext.UNSIGNED_BYTE]: 1, @@ -37,14 +38,20 @@ export interface ProgramDefinition { ATTRIBUTES: Array; } -export abstract class AbstractProgram { +export abstract class AbstractProgram { // eslint-disable-next-line @typescript-eslint/no-empty-function - constructor(_gl: WebGLRenderingContext, _renderer: Sigma) {} + constructor(_gl: WebGLRenderingContext, _renderer: Sigma) {} abstract reallocate(capacity: number): void; abstract render(params: RenderParams): void; } -export abstract class Program implements AbstractProgram, ProgramDefinition { +export abstract class Program< + N extends Attributes = Attributes, + E extends Attributes = Attributes, + Uniform extends string = string, + > + implements AbstractProgram, ProgramDefinition +{ VERTICES: number; ARRAY_ITEMS_PER_VERTEX: number; VERTEX_SHADER_SOURCE: string; diff --git a/src/rendering/webgl/programs/edge.arrowHead.ts b/src/rendering/webgl/programs/edge.arrowHead.ts index 9f0db549a..4f770be66 100644 --- a/src/rendering/webgl/programs/edge.arrowHead.ts +++ b/src/rendering/webgl/programs/edge.arrowHead.ts @@ -5,6 +5,7 @@ * Program rendering direction arrows as a simple triangle. * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, EdgeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; @@ -15,7 +16,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix", "u_sizeRatio", "u_correctionRatio"] as const; -export default class EdgeArrowHeadProgram extends EdgeProgram { +export default class EdgeArrowHeadProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends EdgeProgram { getDefinition() { return { VERTICES: 3, diff --git a/src/rendering/webgl/programs/edge.line.ts b/src/rendering/webgl/programs/edge.line.ts index 308d40cae..c07237a71 100644 --- a/src/rendering/webgl/programs/edge.line.ts +++ b/src/rendering/webgl/programs/edge.line.ts @@ -6,6 +6,7 @@ * won't render thickness correctly on some GPUs and has some quirks. * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, EdgeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; @@ -16,7 +17,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix"] as const; -export default class EdgeLineProgram extends EdgeProgram { +export default class EdgeLineProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends EdgeProgram { getDefinition() { return { VERTICES: 2, diff --git a/src/rendering/webgl/programs/edge.rectangle.ts b/src/rendering/webgl/programs/edge.rectangle.ts index 7ec4f5134..4a807714e 100644 --- a/src/rendering/webgl/programs/edge.rectangle.ts +++ b/src/rendering/webgl/programs/edge.rectangle.ts @@ -15,6 +15,7 @@ * the CPU & GPU (normals are computed on the CPU side). * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, EdgeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; @@ -25,7 +26,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix", "u_zoomRatio", "u_sizeRatio", "u_correctionRatio"] as const; -export default class EdgeRectangleProgram extends EdgeProgram { +export default class EdgeRectangleProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends EdgeProgram { getDefinition() { return { VERTICES: 4, diff --git a/src/rendering/webgl/programs/edge.triangle.ts b/src/rendering/webgl/programs/edge.triangle.ts index 57f5f11c1..e7b9eb915 100644 --- a/src/rendering/webgl/programs/edge.triangle.ts +++ b/src/rendering/webgl/programs/edge.triangle.ts @@ -5,6 +5,7 @@ * Program rendering directed edges as a single triangle. * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, EdgeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import { EdgeProgram } from "./common/edge"; @@ -15,7 +16,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_matrix", "u_sizeRatio", "u_correctionRatio"] as const; -export default class EdgeTriangleProgram extends EdgeProgram { +export default class EdgeTriangleProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends EdgeProgram { getDefinition() { return { VERTICES: 3, diff --git a/src/rendering/webgl/programs/node.circle.ts b/src/rendering/webgl/programs/node.circle.ts index d14db84a5..aec2bc895 100644 --- a/src/rendering/webgl/programs/node.circle.ts +++ b/src/rendering/webgl/programs/node.circle.ts @@ -8,6 +8,7 @@ * indicating which "corner" of the triangle to draw. * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import { NodeProgram } from "./common/node"; @@ -18,7 +19,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_sizeRatio", "u_correctionRatio", "u_matrix"] as const; -export default class NodeCircleProgram extends NodeProgram { +export default class NodeCircleProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends NodeProgram { static readonly ANGLE_1 = 0; static readonly ANGLE_2 = (2 * Math.PI) / 3; static readonly ANGLE_3 = (4 * Math.PI) / 3; diff --git a/src/rendering/webgl/programs/node.image.ts b/src/rendering/webgl/programs/node.image.ts index 41f966e7f..664e65c13 100644 --- a/src/rendering/webgl/programs/node.image.ts +++ b/src/rendering/webgl/programs/node.image.ts @@ -6,6 +6,7 @@ * the classic colored disc. * @module */ +import { Attributes } from "graphology-types"; import { Coordinates, Dimensions, NodeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import VERTEX_SHADER_SOURCE from "../shaders/node.image.vert.glsl"; @@ -200,7 +201,10 @@ export default function getNodeImageProgram(): NodeProgramConstructor { const UNIFORMS = ["u_sizeRatio", "u_pixelRatio", "u_matrix", "u_atlas"] as const; - return class NodeImageProgram extends NodeProgram { + return class NodeImageProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, + > extends NodeProgram { getDefinition() { return { VERTICES: 1, diff --git a/src/rendering/webgl/programs/node.point.ts b/src/rendering/webgl/programs/node.point.ts index ff9b3ff26..f162086d2 100644 --- a/src/rendering/webgl/programs/node.point.ts +++ b/src/rendering/webgl/programs/node.point.ts @@ -7,6 +7,7 @@ * every GPU. * @module */ +import { Attributes } from "graphology-types"; import { NodeDisplayData, RenderParams } from "../../../types"; import { floatColor } from "../../../utils"; import { NodeProgram } from "./common/node"; @@ -17,7 +18,10 @@ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext; const UNIFORMS = ["u_sizeRatio", "u_pixelRatio", "u_matrix"] as const; -export default class NodePointProgram extends NodeProgram { +export default class NodePointProgram< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends NodeProgram { getDefinition() { return { VERTICES: 1, diff --git a/src/settings.ts b/src/settings.ts index 1ae68ed23..150d05243 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -22,7 +22,7 @@ import { NodeProgramConstructor } from "./rendering/webgl/programs/common/node"; * Sigma.js settings * ================================= */ -export interface Settings { +export interface Settings { // Performance hideEdgesOnMove: boolean; hideLabelsOnMove: boolean; @@ -52,8 +52,8 @@ export interface Settings { labelGridCellSize: number; labelRenderedSizeThreshold: number; // Reducers - nodeReducer: null | ((node: string, data: Attributes) => Partial); - edgeReducer: null | ((edge: string, data: Attributes) => Partial); + nodeReducer: null | ((node: string, data: N) => Partial); + edgeReducer: null | ((edge: string, data: E) => Partial); // Features zIndex: boolean; minCameraRatio: null | number; @@ -66,9 +66,9 @@ export interface Settings { allowInvalidContainer: boolean; // Program classes - nodeProgramClasses: { [type: string]: NodeProgramConstructor }; - nodeHoverProgramClasses: { [type: string]: NodeProgramConstructor }; - edgeProgramClasses: { [type: string]: EdgeProgramConstructor }; + nodeProgramClasses: { [type: string]: NodeProgramConstructor }; + nodeHoverProgramClasses: { [type: string]: NodeProgramConstructor }; + edgeProgramClasses: { [type: string]: EdgeProgramConstructor }; } export const DEFAULT_SETTINGS: Settings = { @@ -135,7 +135,10 @@ export const DEFAULT_EDGE_PROGRAM_CLASSES = { line: EdgeRectangleProgram, }; -export function validateSettings(settings: Settings): void { +export function validateSettings< + NodeAttributes extends Attributes = Attributes, + EdgeAttributes extends Attributes = Attributes, +>(settings: Settings): void { if (typeof settings.labelDensity !== "number" || settings.labelDensity < 0) { throw new Error("Settings: invalid `labelDensity`. Expecting a positive number."); } @@ -148,8 +151,10 @@ export function validateSettings(settings: Settings): void { } } -export function resolveSettings(settings: Partial): Settings { - const resolvedSettings = assign({}, DEFAULT_SETTINGS, settings); +export function resolveSettings( + settings: Partial>, +): Settings { + const resolvedSettings = assign({}, DEFAULT_SETTINGS as Settings, settings); resolvedSettings.nodeProgramClasses = assign({}, DEFAULT_NODE_PROGRAM_CLASSES, resolvedSettings.nodeProgramClasses); resolvedSettings.edgeProgramClasses = assign({}, DEFAULT_EDGE_PROGRAM_CLASSES, resolvedSettings.edgeProgramClasses); diff --git a/src/sigma.ts b/src/sigma.ts index 416c00c0e..3b0cf7ec1 100644 --- a/src/sigma.ts +++ b/src/sigma.ts @@ -3,7 +3,7 @@ * ======== * @module */ -import Graph from "graphology-types"; +import Graph, { Attributes } from "graphology-types"; import extend from "@yomguithereal/helpers/extend"; import Camera from "./core/camera"; @@ -53,7 +53,11 @@ const Y_LABEL_MARGIN = 50; /** * Important functions. */ -function applyNodeDefaults(settings: Settings, key: string, data: Partial): NodeDisplayData { +function applyNodeDefaults( + settings: Settings, + key: string, + data: Partial, +): NodeDisplayData { if (!data.hasOwnProperty("x") || !data.hasOwnProperty("y")) throw new Error( `Sigma: could not find a valid position (x, y) for node "${key}". All your nodes must have a number "x" and "y". Maybe your forgot to apply a layout or your "nodeReducer" is not returning the correct data?`, @@ -81,7 +85,11 @@ function applyNodeDefaults(settings: Settings, key: string, data: Partial): EdgeDisplayData { +function applyEdgeDefaults( + settings: Settings, + key: string, + data: Partial, +): EdgeDisplayData { if (!data.color) data.color = settings.defaultEdgeColor; if (!data.label) data.label = ""; @@ -153,9 +161,12 @@ export type SigmaEvents = SigmaStageEvents & SigmaNodeEvents & SigmaEdgeEvents & * @param {HTMLElement} container - DOM container in which to render. * @param {object} settings - Optional settings. */ -export default class Sigma extends TypedEventEmitter { - private settings: Settings; - private graph: GraphType; +export default class Sigma< + N extends Attributes = Attributes, + E extends Attributes = Attributes, +> extends TypedEventEmitter { + private settings: Settings; + private graph: Graph; private mouseCaptor: MouseCaptor; private touchCaptor: TouchCaptor; private container: HTMLElement; @@ -206,7 +217,7 @@ export default class Sigma extends TypedEventEm private camera: Camera; - constructor(graph: GraphType, container: HTMLElement, settings: Partial = {}) { + constructor(graph: Graph, container: HTMLElement, settings: Partial = {}) { super(); // Resolving settings @@ -776,9 +787,9 @@ export default class Sigma extends TypedEventEm // 4. We apply the normalization function // We shallow copy node data to avoid dangerous behaviors from reducers - let attr = Object.assign({}, graph.getNodeAttributes(node)); + let attr = Object.assign({}, graph.getNodeAttributes(node)) as Partial; - if (settings.nodeReducer) attr = settings.nodeReducer(node, attr); + if (settings.nodeReducer) attr = settings.nodeReducer(node, attr as N); const data = applyNodeDefaults(this.settings, node, attr); @@ -844,9 +855,9 @@ export default class Sigma extends TypedEventEm // 3. We apply our defaults, while running some vital checks // We shallow copy edge data to avoid dangerous behaviors from reducers - let attr = Object.assign({}, graph.getEdgeAttributes(edge)); + let attr = Object.assign({}, graph.getEdgeAttributes(edge)) as Partial; - if (settings.edgeReducer) attr = settings.edgeReducer(edge, attr); + if (settings.edgeReducer) attr = settings.edgeReducer(edge, attr as E); const data = applyEdgeDefaults(this.settings, edge, attr); @@ -1285,7 +1296,7 @@ export default class Sigma extends TypedEventEm * * @return {Graph} */ - getGraph(): GraphType { + getGraph(): Graph { return this.graph; } @@ -1294,7 +1305,7 @@ export default class Sigma extends TypedEventEm * * @return {Graph} */ - setGraph(graph: GraphType): void { + setGraph(graph: Graph): void { if (graph === this.graph) return; // Unbinding handlers on the current graph @@ -1417,7 +1428,7 @@ export default class Sigma extends TypedEventEm * * @return {Settings} A copy of the settings collection. */ - getSettings(): Settings { + getSettings(): Settings { return { ...this.settings }; } @@ -1427,7 +1438,7 @@ export default class Sigma extends TypedEventEm * @param {string} key - The setting key to get. * @return {any} The value attached to this setting key or undefined if not found */ - getSetting(key: K): Settings[K] | undefined { + getSetting>(key: K): Settings[K] | undefined { return this.settings[key]; } @@ -1439,7 +1450,7 @@ export default class Sigma extends TypedEventEm * @param {any} value - The value to set. * @return {Sigma} */ - setSetting(key: K, value: Settings[K]): this { + setSetting>(key: K, value: Settings[K]): this { this.settings[key] = value; validateSettings(this.settings); this.handleSettingsUpdate(); @@ -1455,7 +1466,10 @@ export default class Sigma extends TypedEventEm * @param {function} updater - The update function. * @return {Sigma} */ - updateSetting(key: K, updater: (value: Settings[K]) => Settings[K]): this { + updateSetting>( + key: K, + updater: (value: Settings[K]) => Settings[K], + ): this { this.settings[key] = updater(this.settings[key]); validateSettings(this.settings); this.handleSettingsUpdate();