diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..ae20ff6 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +dist +demo \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 91f5c6b..304ae07 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,41 +1,56 @@ module.exports = { - extends: 'standard', - env: { - browser: true, - 'es6': true - }, - globals: { - 'Image': true, - 'Canvas': true - }, - rules: { - // allow paren-less arrow functions - 'arrow-parens': 'off', - // allow async-await - 'generator-star-spacing': 'off', - // allow debugger during development - 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', - //Allow semi colons - 'semi': ['error', 'always'], - //Tab indentation - 'indent': ['error', 'tab', { 'SwitchCase': 1, 'FunctionDeclaration': { 'body': 1, 'parameters': 2 } }], - 'no-trailing-spaces': ['error', { 'skipBlankLines': true, 'ignoreComments': true }], - 'no-tabs': 'off', - 'no-mixed-spaces-and-tabs': ['error', 'smart-tabs'], - 'no-multiple-empty-lines': ['error', { 'max': 2, 'maxEOF': 1 }], - "no-global-assign": ["error", {"exceptions": ["window", "document"]}], - 'no-mixed-operators': [ - 'error', - { - 'groups': [ - ['+', '-', '*', '/', '%', '**'], - ['&', '|', '^', '~', '<<', '>>', '>>>'], - ['==', '!=', '===', '!==', '>', '>=', '<', '<='], - ['&&', '||'], - ['in', 'instanceof'] - ], - 'allowSamePrecedence': true - } - ] - } + root: true, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + ], + env: { + browser: true, + es6: true, + }, + globals: { + Image: true, + Canvas: true, + }, + rules: { + // allow paren-less arrow functions + "arrow-parens": "off", + // allow async-await + "generator-star-spacing": "off", + // allow debugger during development + "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", + //Allow semi colons + semi: ["error", "always"], + //Tab indentation + indent: [ + "error", + "tab", + { SwitchCase: 1, FunctionDeclaration: { body: 1, parameters: 2 } }, + ], + "no-trailing-spaces": [ + "error", + { skipBlankLines: true, ignoreComments: true }, + ], + "no-tabs": "off", + // "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], + "no-mixed-spaces-and-tabs": "off", + "no-multiple-empty-lines": ["error", { max: 2, maxEOF: 1 }], + "no-global-assign": ["error", { exceptions: ["window", "document"] }], + // "no-mixed-operators": [ + // "error", + // { + // groups: [ + // ["+", "-", "*", "/", "%", "**"], + // ["&", "|", "^", "~", "<<", ">>", ">>>"], + // ["==", "!=", "===", "!==", ">", ">=", "<", "<="], + // ["&&", "||"], + // ["in", "instanceof"], + // ], + // allowSamePrecedence: true, + // }, + // ], + }, }; diff --git a/README.md b/README.md index a96e2c5..2ae9a42 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Api to set point radius. Accepts float value as an input. Try [Example](https://nswamy14.github.io/visual-heatmap/demo/heatmap3.html) ### instance.setGradient(gradient) -Api to set color gradient. Accepts array of objects with color, value and offset. +Api to set color gradient. Accepts array of objects with color value and offset. ### instance.setIntensity(number) Api to set Intensity factor. Accepts float value as an input. diff --git a/dist/heatmap.d.ts b/dist/heatmap.d.ts new file mode 100644 index 0000000..1ef1d11 --- /dev/null +++ b/dist/heatmap.d.ts @@ -0,0 +1,109 @@ +import { HeatmapRenderer } from "./heatmapRenderer"; +import { BackgroundImageConfig, GradientElement, HeatmapConfig, Point, Translate } from "./types"; +export declare class Heatmap { + private renderer; + ctx: WebGL2RenderingContext | null; + ratio: number; + width: number; + height: number; + min: number; + max: number; + size: number; + zoom: number; + angle: number; + intensity: number; + translate: [number, number]; + opacity: number; + gradient: import("./types").MappedGradient | null; + imageConfig: BackgroundImageConfig | null; + constructor(context: string | HTMLElement, config: HeatmapConfig); + /** + * Set the maximum data value for relative gradient calculations + * @param max - number + * @returns instance + */ + setMax(max: number): HeatmapRenderer; + /** + * Set the minimum data value for relative gradient calculations + * @param min - number + * @returns instance + */ + setMin(min: number): HeatmapRenderer; + /** + * Accepts array of objects with color value and offset + * @param gradient - Color Gradient + * @returns instance + */ + setGradient(gradient: GradientElement[]): HeatmapRenderer; + /** + * Set the translate transformation on the canvas + * @param translate - Accepts array [x, y] + * @returns instance + */ + setTranslate(translate: Translate): HeatmapRenderer; + /** + * Set the zoom transformation on the canvas + * @param zoom - Accepts float value + * @returns instance + */ + setZoom(zoom: number): HeatmapRenderer; + /** + * Set the rotation transformation on the canvas + * @param angle - Accepts angle in radians + * @returns instance + */ + setRotationAngle(angle: number): HeatmapRenderer; + /** + * Set the point radius + * @param size - Accepts float value + * @returns instance + */ + setSize(size: number): HeatmapRenderer; + /** + * Set the intensity factor + * @param intensity - Accepts float value + * @returns instance + */ + setIntensity(intensity: number): HeatmapRenderer; + /** + * Set the opacity factor + * @param opacity - The opacity factor. + * @returns instance + */ + setOpacity(opacity: number): HeatmapRenderer; + /** + * Set the background image + * @param config - Accepts Object with { Url, height, width, x, and y} properties + * @returns instance + */ + setBackgroundImage(config: BackgroundImageConfig): HeatmapRenderer | undefined; + /** + * After adding data points, need to invoke .render() method to update the heatmap + * @param data - The data points with 'x', 'y' and 'value' + * @param transIntactFlag - Flag indicating whether to apply existing heatmap transformations on the newly added data points + * @returns instance + */ + addData(data: Point[], transIntactFlag: boolean): HeatmapRenderer; + /** + * @param data - Accepts an array of data points with 'x', 'y' and 'value' + * @returns instance + */ + renderData(data: Point[]): HeatmapRenderer; + /** + * Method to re-render the heatmap. This method needs to be invoked as and when configurations get changed + */ + render(): void; + /** + * Get projected co-ordinates relative to the heatmap layer + * @param data - The data point to project. + * @returns projected data point. + */ + projection(data: Point): { + x: number; + y: number; + }; + /** + * Clears canvas + */ + clear(): void; +} diff --git a/dist/heatmapRenderer.d.ts b/dist/heatmapRenderer.d.ts new file mode 100644 index 0000000..b2e385b --- /dev/null +++ b/dist/heatmapRenderer.d.ts @@ -0,0 +1,56 @@ +import { BackgroundImageConfig, GradientElement, HearmapExData, HeatmapConfig, MappedGradient, Point, ShaderProgram, Translate } from "./types"; +export declare class HeatmapRenderer { + ctx: WebGL2RenderingContext | null; + ratio: number; + width: number; + height: number; + imageConfig: BackgroundImageConfig | null; + configMin: number | null; + configMax: number | null; + min: number; + max: number; + hearmapExData: HearmapExData | object; + gradShadOP: ShaderProgram; + colorShadOP: ShaderProgram; + imageShaOP: ShaderProgram; + fbTexObj: WebGLTexture; + fbo: WebGLFramebuffer; + size: number; + zoom: number; + angle: number; + intensity: number; + translate: [number, number]; + opacity: number; + gradient: MappedGradient | null; + imageTexture: WebGLTexture | null; + pLen: number | undefined; + buffer: ArrayBuffer | undefined; + buffer2: ArrayBuffer | undefined; + private layer; + private dom; + private imgWidth; + private imgHeight; + private heatmapData; + private type; + constructor(container: string | HTMLElement, config: HeatmapConfig); + resize(): void; + clear(): void; + setMax(max: number): HeatmapRenderer; + setMin(min: number): HeatmapRenderer; + setGradient(gradient: GradientElement[]): HeatmapRenderer; + setTranslate(translate: Translate): this; + setZoom(zoom: number): HeatmapRenderer; + setRotationAngle(angle: number): HeatmapRenderer; + setSize(size: number): HeatmapRenderer; + setIntensity(intensity: number): HeatmapRenderer; + setOpacity(opacity: number): HeatmapRenderer; + setBackgroundImage(config: BackgroundImageConfig): this | undefined; + clearData(): void; + addData(data: Point[], transIntactFlag: boolean): HeatmapRenderer; + renderData(data: Point[]): HeatmapRenderer; + render(): void; + projection(data: Point): { + x: number; + y: number; + }; +} diff --git a/dist/main.d.ts b/dist/main.d.ts new file mode 100644 index 0000000..9331b8b --- /dev/null +++ b/dist/main.d.ts @@ -0,0 +1,3 @@ +import { Heatmap } from "./heatmap"; +import { HeatmapConfig } from "./types"; +export default function (context: string | HTMLElement, config: HeatmapConfig): Heatmap; diff --git a/dist/shaders.d.ts b/dist/shaders.d.ts new file mode 100644 index 0000000..2c39587 --- /dev/null +++ b/dist/shaders.d.ts @@ -0,0 +1,12 @@ +export declare const GradShader: { + vertex: string; + fragment: string; +}; +export declare const ColorShader: { + vertex: string; + fragment: string; +}; +export declare const ImageShader: { + vertex: string; + fragment: string; +}; diff --git a/dist/types.d.ts b/dist/types.d.ts new file mode 100644 index 0000000..5af0790 --- /dev/null +++ b/dist/types.d.ts @@ -0,0 +1,65 @@ +export type JavaScriptDataType = number | string | boolean | null | undefined | symbol | bigint | object; +export type ShaderTypes = "VERTEX_SHADER" | "FRAGMENT_SHADER"; +export type Shader = { + vertex: string; + fragment: string; +}; +export interface ShaderProgram { + program: WebGLProgram; + attr: { + bufferType: GLenum; + buffer: WebGLBuffer; + drawType: GLenum; + valueType: GLenum; + size: GLint; + attribute: number; + data: Float32Array; + }[]; + uniform: { + [key: string]: WebGLUniformLocation | null; + }; +} +export type Color = [number, number, number, number?]; +export interface GradientElement { + color: Color; + offset: number; +} +export interface MappedGradient { + value: Float32Array; + length: number; + offset: number[]; +} +export interface Point { + x: number; + y: number; + value: number; +} +export type HeatmapConfig = { + size?: number; + max?: number; + min?: number; + intensity?: number; + translate?: [number, number]; + zoom?: number; + angle?: number; + opacity?: number; + gradient: GradientElement[]; + backgroundImage?: BackgroundImageConfig; +}; +export type HearmapExData = { + posVec: Float32Array; + rVec: Float32Array; + minMax: { + min: number; + max: number; + }; +}; +export interface BackgroundImageConfig { + url?: string; + width?: number; + height?: number; + x: number; + y: number; + image?: HTMLImageElement; +} +export type Translate = [number, number]; diff --git a/dist/utils/shaderUtils.d.ts b/dist/utils/shaderUtils.d.ts new file mode 100644 index 0000000..b7bcc08 --- /dev/null +++ b/dist/utils/shaderUtils.d.ts @@ -0,0 +1,4 @@ +import { Shader, ShaderProgram } from "../types"; +export declare const createImageShader: (ctx: WebGL2RenderingContext, shader: Shader) => ShaderProgram; +export declare const createGradiantShader: (ctx: WebGL2RenderingContext, shader: Shader) => ShaderProgram; +export declare const createColorShader: (ctx: WebGL2RenderingContext, shader: Shader) => ShaderProgram; diff --git a/dist/utils/utils.d.ts b/dist/utils/utils.d.ts new file mode 100644 index 0000000..d918dcb --- /dev/null +++ b/dist/utils/utils.d.ts @@ -0,0 +1,6 @@ +import { JavaScriptDataType } from "../types"; +export declare function isNullUndefined(val: unknown): val is null | undefined; +export declare function isNotNumber(val: unknown): val is Exclude; +export declare function isSortedAscending(arr: any[]): boolean; +/** @see https://codereview.chromium.org/156833002/ */ +export declare function getPixelRatio(ctx: any): number; diff --git a/dist/visualHeatmap.esm.js b/dist/visualHeatmap.esm.js index 227d26f..95a8d8f 100644 --- a/dist/visualHeatmap.esm.js +++ b/dist/visualHeatmap.esm.js @@ -4,618 +4,971 @@ * @license BSD-3-Clause */ const GradShader = { - vertex: "#version 300 es\n\t\t\t\tin vec2 a_position;\n\t\t\t\tin float a_intensity;\n\t\t\t\tuniform float u_size;\n\t\t\t\tuniform vec2 u_resolution;\n\t\t\t\tuniform vec2 u_translate; \n\t\t\t\tuniform float u_zoom; \n\t\t\t\tuniform float u_angle; \n\t\t\t\tuniform float u_density;\n\t\t\t\tout float v_i;\n\n\t\t\t\tvec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 rotationMat = mat2(c, -s, s, c); \n\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\treturn scaleMatInv * rotationMat * scaleMat * v;\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\tfloat zoomFactor = max(u_zoom, 0.1);\n\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle, u_resolution.x / u_resolution.y);\n\t\t\t\t\t}\n\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\tgl_PointSize = u_size * u_density;\n\t\t\t\t\tv_i = a_intensity;\n\t\t\t\t}", - fragment: "#version 300 es\n\t\t\t\tprecision mediump float;\n\t\t\t\tuniform float u_max;\n\t\t\t\tuniform float u_min;\n\t\t\t\tuniform float u_intensity;\n\t\t\t\tin float v_i;\n\t\t\t\tout vec4 fragColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat r = 0.0; \n\t\t\t\t\tvec2 cxy = 2.0 * gl_PointCoord - 1.0;\n\t\t\t\t\tr = dot(cxy, cxy);\n\t\t\t\t\tfloat deno = max(u_max - u_min, 1.0);\n\t\t\t\t\tif(r <= 1.0) {\n\t\t\t\t\t\tfragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r)));\n\t\t\t\t\t}\n\t\t\t\t}" + vertex: `#version 300 es + in vec2 a_position; + in float a_intensity; + uniform float u_size; + uniform vec2 u_resolution; + uniform vec2 u_translate; + uniform float u_zoom; + uniform float u_angle; + uniform float u_density; + out float v_i; + + vec2 rotation(vec2 v, float a, float aspect) { + float s = sin(a); float c = cos(a); mat2 rotationMat = mat2(c, -s, s, c); + mat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0); + mat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0); + return scaleMatInv * rotationMat * scaleMat * v; + } + + void main() { + vec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution); + vec2 zeroToTwo = zeroToOne * 2.0 - 1.0; + float zoomFactor = max(u_zoom, 0.1); + zeroToTwo = zeroToTwo / zoomFactor; + if (u_angle != 0.0) { + zeroToTwo = rotation(zeroToTwo, u_angle, u_resolution.x / u_resolution.y); + } + gl_Position = vec4(zeroToTwo , 0, 1); + gl_PointSize = u_size * u_density; + v_i = a_intensity; + }`, + fragment: `#version 300 es + precision mediump float; + uniform float u_max; + uniform float u_min; + uniform float u_intensity; + in float v_i; + out vec4 fragColor; + void main() { + float r = 0.0; + vec2 cxy = 2.0 * gl_PointCoord - 1.0; + r = dot(cxy, cxy); + float deno = max(u_max - u_min, 1.0); + if(r <= 1.0) { + fragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r))); + } + }`, }; const ColorShader = { - vertex: "#version 300 es\n\t\t\t\tprecision highp float;\n\t\t\t\tin vec2 a_texCoord;\n\t\t\t\tout vec2 v_texCoord;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 clipSpace = a_texCoord * 2.0 - 1.0;\n\t\t\t\t\tgl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\t\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t\t}\n\t", - fragment: "#version 300 es\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t\tin vec2 v_texCoord;\n\t\t\t\t\tout vec4 fragColor;\n\t\t\t\t\tuniform sampler2D u_framebuffer;\n\t\t\t\t\tuniform vec4 u_colorArr[20];\n\t\t\t\t\tuniform float u_colorCount;\n\t\t\t\t\tuniform float u_opacity;\n\t\t\t\t\tuniform float u_offset[20];\n\n\t\t\t\t\tfloat remap ( float minval, float maxval, float curval ) {\n\t\t\t\t\t\treturn ( curval - minval ) / ( maxval - minval );\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid main() {\n\t\t\t\t\t\tfloat alpha = texture(u_framebuffer, v_texCoord.xy).a;\n\t\t\t\t\t\tif (alpha > 0.0 && alpha <= 1.0) {\n\t\t\t\t\t\t\tvec4 color_;\n\n\t\t\t\t\t\t\tif (alpha <= u_offset[0]) {\n\t\t\t\t\t\t\t\tcolor_ = u_colorArr[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= 20; ++i) {\n\t\t\t\t\t\t\t\t\tif (alpha <= u_offset[i]) {\n\t\t\t\t\t\t\t\t\t\tcolor_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) );\n\t\t\t\t\t\t\t\t\t\tcolor_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha ));\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcolor_ = color_ * u_opacity;\n\t\t\t\t\t\t\tif (color_.a < 0.0) {\n\t\t\t\t\t\t\t\tcolor_.a = 0.0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfragColor = color_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t" + vertex: `#version 300 es + precision highp float; + in vec2 a_texCoord; + out vec2 v_texCoord; + void main() { + vec2 clipSpace = a_texCoord * 2.0 - 1.0; + gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); + v_texCoord = a_texCoord; + } + `, + fragment: `#version 300 es + precision mediump float; + in vec2 v_texCoord; + out vec4 fragColor; + uniform sampler2D u_framebuffer; + uniform vec4 u_colorArr[20]; + uniform float u_colorCount; + uniform float u_opacity; + uniform float u_offset[20]; + + float remap ( float minval, float maxval, float curval ) { + return ( curval - minval ) / ( maxval - minval ); + } + + void main() { + float alpha = texture(u_framebuffer, v_texCoord.xy).a; + if (alpha > 0.0 && alpha <= 1.0) { + vec4 color_; + + if (alpha <= u_offset[0]) { + color_ = u_colorArr[0]; + } else { + for (int i = 1; i <= 20; ++i) { + if (alpha <= u_offset[i]) { + color_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) ); + color_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha )); + + break; + } + } + } + + color_ = color_ * u_opacity; + if (color_.a < 0.0) { + color_.a = 0.0; + } + fragColor = color_; + } else { + fragColor = vec4(0.0, 0.0, 0.0, 0.0); + } + } + `, }; const ImageShader = { - vertex: "#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n uniform vec2 u_resolution;\n\t\t\t\t\tuniform vec2 u_translate; \n\t\t\t\t\tuniform float u_zoom; \n\t\t\t\t\tuniform float u_angle; \n\t\t\t\t\tuniform float u_density;\n out vec2 v_texCoord;\n\n vec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c);\n\t\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\treturn scaleMatInv * m * scaleMat * v;\n\t\t\t\t\t}\n\n void main() {\n \tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n \tzeroToOne.y = 1.0 - zeroToOne.y;\n\t\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\t\tfloat zoomFactor = u_zoom;\n\t\t\t\t\t\tif (zoomFactor == 0.0) {\n\t\t\t\t\t\t\tzoomFactor = 0.1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\t\tv_texCoord = a_texCoord;\n }\n \t\t", - fragment: "#version 300 es\n precision mediump float;\n uniform sampler2D u_image;\n in vec2 v_texCoord;\n out vec4 fragColor;\n void main() {\n fragColor = texture(u_image, v_texCoord);\n }\n " + vertex: `#version 300 es + precision highp float; + in vec2 a_position; + in vec2 a_texCoord; + uniform vec2 u_resolution; + uniform vec2 u_translate; + uniform float u_zoom; + uniform float u_angle; + uniform float u_density; + out vec2 v_texCoord; + + vec2 rotation(vec2 v, float a, float aspect) { + float s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c); + mat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0); + mat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0); + return scaleMatInv * m * scaleMat * v; + } + + void main() { + vec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution); + zeroToOne.y = 1.0 - zeroToOne.y; + vec2 zeroToTwo = zeroToOne * 2.0 - 1.0; + float zoomFactor = u_zoom; + if (zoomFactor == 0.0) { + zoomFactor = 0.1; + } + zeroToTwo = zeroToTwo / zoomFactor; + if (u_angle != 0.0) { + zeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y); + } + + gl_Position = vec4(zeroToTwo , 0, 1); + v_texCoord = a_texCoord; + } + `, + fragment: `#version 300 es + precision mediump float; + uniform sampler2D u_image; + in vec2 v_texCoord; + out vec4 fragColor; + void main() { + fragColor = texture(u_image, v_texCoord); + } + `, }; function createShader(ctx, type, src) { - var shader = ctx.createShader(ctx[type]); - ctx.shaderSource(shader, src); - ctx.compileShader(shader); - var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); - if (!compiled) { - var lastError = ctx.getShaderInfoLog(shader); - ctx.deleteShader(shader); - throw new Error("*** Error compiling shader '" + shader + "':" + lastError); - } - return shader; + const shader = ctx.createShader(ctx[type]); + if (!shader) { + throw new Error("Failed to create shader."); + } + ctx.shaderSource(shader, src); + ctx.compileShader(shader); + const compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); + if (!compiled) { + const lastError = ctx.getShaderInfoLog(shader); + ctx.deleteShader(shader); + throw new Error("*** Error compiling shader '" + shader + "':" + lastError); + } + return shader; } function createProgram(ctx, shader) { - var vshader = createShader(ctx, 'VERTEX_SHADER', shader.vertex); - var fshader = createShader(ctx, 'FRAGMENT_SHADER', shader.fragment); - var program = ctx.createProgram(); - ctx.attachShader(program, vshader); - ctx.attachShader(program, fshader); - ctx.linkProgram(program); - var linked = ctx.getProgramParameter(program, ctx.LINK_STATUS); - if (!linked) { - var lastError = ctx.getProgramInfoLog(program); - ctx.deleteProgram(program); - throw new Error('Error in program linking:' + lastError); - } else { - return program; - } + const vshader = createShader(ctx, "VERTEX_SHADER", shader.vertex); + const fshader = createShader(ctx, "FRAGMENT_SHADER", shader.fragment); + const program = ctx.createProgram(); + if (!program) { + throw new Error("Failed to create program."); + } + ctx.attachShader(program, vshader); + ctx.attachShader(program, fshader); + ctx.linkProgram(program); + const linked = ctx.getProgramParameter(program, ctx.LINK_STATUS); + if (!linked) { + const lastError = ctx.getProgramInfoLog(program); + ctx.deleteProgram(program); + throw new Error("Error in program linking:" + lastError); + } + else { + return program; + } } const createImageShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_position'), - data: new Float32Array([]) - }, { - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_texCoord'), - data: new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]) - }], - uniform: { - u_resolution: ctx.getUniformLocation(program, 'u_resolution'), - u_image: ctx.getUniformLocation(program, 'u_image'), - u_translate: ctx.getUniformLocation(program, 'u_translate'), - u_zoom: ctx.getUniformLocation(program, 'u_zoom'), - u_angle: ctx.getUniformLocation(program, 'u_angle'), - u_density: ctx.getUniformLocation(program, 'u_density') - } - }; + const program = createProgram(ctx, shader); + const positionBuffer = ctx.createBuffer(); + if (!positionBuffer) { + throw new Error("Failed to create position buffer."); + } + const texCoordBuffer = ctx.createBuffer(); + if (!texCoordBuffer) { + throw new Error("Failed to create texture coordinate buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: positionBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_position"), + data: new Float32Array([]), + }, + { + bufferType: ctx.ARRAY_BUFFER, + buffer: texCoordBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_texCoord"), + data: new Float32Array([ + 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, + ]), + }, + ], + uniform: { + u_resolution: ctx.getUniformLocation(program, "u_resolution"), + u_image: ctx.getUniformLocation(program, "u_image"), + u_translate: ctx.getUniformLocation(program, "u_translate"), + u_zoom: ctx.getUniformLocation(program, "u_zoom"), + u_angle: ctx.getUniformLocation(program, "u_angle"), + u_density: ctx.getUniformLocation(program, "u_density"), + }, + }; }; const createGradiantShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_position'), - data: new Float32Array([]) - }, { - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 1, - attribute: ctx.getAttribLocation(program, 'a_intensity'), - data: new Float32Array([]) - }], - uniform: { - u_resolution: ctx.getUniformLocation(program, 'u_resolution'), - u_max: ctx.getUniformLocation(program, 'u_max'), - u_min: ctx.getUniformLocation(program, 'u_min'), - u_size: ctx.getUniformLocation(program, 'u_size'), - u_intensity: ctx.getUniformLocation(program, 'u_intensity'), - u_translate: ctx.getUniformLocation(program, 'u_translate'), - u_zoom: ctx.getUniformLocation(program, 'u_zoom'), - u_angle: ctx.getUniformLocation(program, 'u_angle'), - u_density: ctx.getUniformLocation(program, 'u_density') - } - }; + const program = createProgram(ctx, shader); + const positionBuffer = ctx.createBuffer(); + if (!positionBuffer) { + throw new Error("Failed to create position buffer."); + } + const intensityBuffer = ctx.createBuffer(); + if (!intensityBuffer) { + throw new Error("Failed to create intensity buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: positionBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_position"), + data: new Float32Array([]), + }, + { + bufferType: ctx.ARRAY_BUFFER, + buffer: intensityBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 1, + attribute: ctx.getAttribLocation(program, "a_intensity"), + data: new Float32Array([]), + }, + ], + uniform: { + u_resolution: ctx.getUniformLocation(program, "u_resolution"), + u_max: ctx.getUniformLocation(program, "u_max"), + u_min: ctx.getUniformLocation(program, "u_min"), + u_size: ctx.getUniformLocation(program, "u_size"), + u_intensity: ctx.getUniformLocation(program, "u_intensity"), + u_translate: ctx.getUniformLocation(program, "u_translate"), + u_zoom: ctx.getUniformLocation(program, "u_zoom"), + u_angle: ctx.getUniformLocation(program, "u_angle"), + u_density: ctx.getUniformLocation(program, "u_density"), + }, + }; }; const createColorShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_texCoord'), - data: new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]) - }], - uniform: { - u_framebuffer: ctx.getUniformLocation(program, 'u_framebuffer'), - u_colorArr: ctx.getUniformLocation(program, 'u_colorArr'), - u_colorCount: ctx.getUniformLocation(program, 'u_colorCount'), - u_opacity: ctx.getUniformLocation(program, 'u_opacity'), - u_offset: ctx.getUniformLocation(program, 'u_offset') - } - }; + const program = createProgram(ctx, shader); + const texCoordBuffer = ctx.createBuffer(); + if (!texCoordBuffer) { + throw new Error("Failed to create texture coordinate buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: texCoordBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_texCoord"), + data: new Float32Array([ + 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, + ]), + }, + ], + uniform: { + u_framebuffer: ctx.getUniformLocation(program, "u_framebuffer"), + u_colorArr: ctx.getUniformLocation(program, "u_colorArr"), + u_colorCount: ctx.getUniformLocation(program, "u_colorCount"), + u_opacity: ctx.getUniformLocation(program, "u_opacity"), + u_offset: ctx.getUniformLocation(program, "u_offset"), + }, + }; }; function isNullUndefined(val) { - return val === null || val === undefined; + return val === null || val === undefined; } function isNotNumber(val) { - return typeof val !== 'number'; + return typeof val !== "number"; } +// eslint-disable-next-line @typescript-eslint/no-explicit-any function isSortedAscending(arr) { - for (let i = 0; i < arr.length - 1; i++) { - if (arr[i + 1].offset - arr[i].offset < 0) { - return false; + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i + 1].offset - arr[i].offset < 0) { + return false; + } } - } - return true; + return true; } -function getPixlRatio(ctx) { - const dpr = window.devicePixelRatio || 1; - const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; - return dpr / bsr; +/** @see https://codereview.chromium.org/156833002/ */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function getPixelRatio(ctx) { + const dpr = window.devicePixelRatio || 1; + const bsr = ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || + 1; + return dpr / bsr; } function gradientMapper(grad) { - if (!Array.isArray(grad) || grad.length < 2) { - throw new Error('Invalid gradient: Expected an array with at least 2 elements.'); - } - if (!isSortedAscending(grad)) { - throw new Error('Invalid gradient: Gradient is not sorted'); - } - const gradLength = grad.length; - const values = new Float32Array(gradLength * 4); - const offsets = new Array(gradLength); - grad.forEach(function (d, i) { - const baseIndex = i * 4; - values[baseIndex] = d.color[0] / 255; - values[baseIndex + 1] = d.color[1] / 255; - values[baseIndex + 2] = d.color[2] / 255; - values[baseIndex + 3] = d.color[3] !== undefined ? d.color[3] : 1.0; - offsets[i] = d.offset; - }); - return { - value: values, - length: gradLength, - offset: offsets - }; + if (!Array.isArray(grad) || grad.length < 2) { + throw new Error("Invalid gradient: Expected an array with at least 2 elements."); + } + if (!isSortedAscending(grad)) { + throw new Error("Invalid gradient: Gradient is not sorted"); + } + const gradLength = grad.length; + const values = new Float32Array(gradLength * 4); + const offsets = new Array(gradLength); + grad.forEach(function (d, i) { + const baseIndex = i * 4; + values[baseIndex] = d.color[0] / 255; + values[baseIndex + 1] = d.color[1] / 255; + values[baseIndex + 2] = d.color[2] / 255; + values[baseIndex + 3] = d.color[3] !== undefined ? d.color[3] : 1.0; + offsets[i] = d.offset; + }); + return { + value: values, + length: gradLength, + offset: offsets, + }; } function extractData(data, self) { - const len = data.length; - let { - posVec = [], - rVec = [] - } = self.hearmapExData || {}; - if (self.pLen !== len) { - self.buffer = new ArrayBuffer(len * 8); - posVec = new Float32Array(self.buffer); - self.buffer2 = new ArrayBuffer(len * 4); - rVec = new Float32Array(self.buffer2); - self.pLen = len; - } - const dataMinMaxValue = { - min: Infinity, - max: -Infinity - }; - for (let i = 0; i < len; i++) { - posVec[i * 2] = data[i].x; - posVec[i * 2 + 1] = data[i].y; - rVec[i] = data[i].value; - if (dataMinMaxValue.min > data[i].value) { - dataMinMaxValue.min = data[i].value; - } - if (dataMinMaxValue.max < data[i].value) { - dataMinMaxValue.max = data[i].value; - } - } - return { - posVec: posVec, - rVec: rVec, - minMax: dataMinMaxValue - }; + const len = data.length; + let { posVec = new Float32Array(), rVec = new Float32Array() } = (self.hearmapExData || {}); + if (self.pLen !== len) { + self.buffer = new ArrayBuffer(len * 8); + posVec = new Float32Array(self.buffer); + self.buffer2 = new ArrayBuffer(len * 4); + rVec = new Float32Array(self.buffer2); + self.pLen = len; + } + const dataMinMaxValue = { + min: Infinity, + max: -Infinity, + }; + for (let i = 0; i < len; i++) { + posVec[i * 2] = data[i].x; + posVec[i * 2 + 1] = data[i].y; + rVec[i] = data[i].value; + if (dataMinMaxValue.min > data[i].value) { + dataMinMaxValue.min = data[i].value; + } + if (dataMinMaxValue.max < data[i].value) { + dataMinMaxValue.max = data[i].value; + } + } + return { + posVec: posVec, + rVec: rVec, + minMax: dataMinMaxValue, + }; } function transCoOr(data) { - const zoomFactor = this.zoom || 0.1; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - const { - angle, - translate - } = this; - - // Combine operations to reduce the number of arithmetic steps - let posX = (data.x - halfWidth) / halfWidth * zoomFactor; - let posY = (data.y - halfHeight) / halfHeight * zoomFactor; - - // Rotate the point if there's an angle - if (angle !== 0.0) { - const cosAngle = Math.cos(angle); - const sinAngle = Math.sin(angle); - posY = sinAngle * posX + cosAngle * posY; - posX = cosAngle * posX - sinAngle * posY; - } - - // Scale back and adjust the position - posX = posX * halfWidth + halfWidth - translate[0]; - posY = posY * halfHeight + halfHeight - translate[1]; - data.x = posX; - data.y = posY; - return { - x: posX, - y: posY - }; + const zoomFactor = this.zoom || 0.1; + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + const { angle, translate } = this; + // Combine operations to reduce the number of arithmetic steps + let posX = ((data.x - halfWidth) / halfWidth) * zoomFactor; + let posY = ((data.y - halfHeight) / halfHeight) * zoomFactor; + // Rotate the point if there's an angle + if (angle !== 0.0) { + const cosAngle = Math.cos(angle); + const sinAngle = Math.sin(angle); + posY = sinAngle * posX + cosAngle * posY; + posX = cosAngle * posX - sinAngle * posY; + } + // Scale back and adjust the position + posX = posX * halfWidth + halfWidth - translate[0]; + posY = posY * halfHeight + halfHeight - translate[1]; + data.x = posX; + data.y = posY; + return { x: posX, y: posY }; } function renderExec() { - const ctx = this.ctx; - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); - ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); - ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, this.width * this.ratio, this.height * this.ratio, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); - ctx.bindFramebuffer(ctx.FRAMEBUFFER, this.fbo); - ctx.framebufferTexture2D(ctx.FRAMEBUFFER, ctx.COLOR_ATTACHMENT0, ctx.TEXTURE_2D, this.fbTexObj, 0); - if (this.hearmapExData) { - renderHeatGrad.call(this, ctx, this.hearmapExData); - } - ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); - if (this.imageConfig) { - renderImage.call(this, ctx, this.imageConfig); - } - renderColorGradiant.call(this, ctx); + const ctx = this.ctx; + if (!ctx) { + return; + } + ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); + ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, this.width * this.ratio, this.height * this.ratio, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); + ctx.bindFramebuffer(ctx.FRAMEBUFFER, this.fbo); + ctx.framebufferTexture2D(ctx.FRAMEBUFFER, ctx.COLOR_ATTACHMENT0, ctx.TEXTURE_2D, this.fbTexObj, 0); + if (this.hearmapExData) { + renderHeatGrad.call(this, ctx, this.hearmapExData); + } + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + if (this.imageConfig) { + renderImage.call(this, ctx, this.imageConfig); + } + renderColorGradiant.call(this, ctx); } function renderHeatGrad(ctx, exData) { - var _exData$minMax$min, _exData$minMax, _exData$minMax$max, _exData$minMax2; - ctx.useProgram(this.gradShadOP.program); - this.min = this.configMin !== null ? this.configMin : (_exData$minMax$min = exData === null || exData === void 0 || (_exData$minMax = exData.minMax) === null || _exData$minMax === void 0 ? void 0 : _exData$minMax.min) !== null && _exData$minMax$min !== void 0 ? _exData$minMax$min : 0; - this.max = this.configMax !== null ? this.configMax : (_exData$minMax$max = exData === null || exData === void 0 || (_exData$minMax2 = exData.minMax) === null || _exData$minMax2 === void 0 ? void 0 : _exData$minMax2.max) !== null && _exData$minMax$max !== void 0 ? _exData$minMax$max : 0; - this.gradShadOP.attr[0].data = exData.posVec || []; - this.gradShadOP.attr[1].data = exData.rVec || []; - ctx.uniform2fv(this.gradShadOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); - ctx.uniform2fv(this.gradShadOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); - ctx.uniform1f(this.gradShadOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); - ctx.uniform1f(this.gradShadOP.uniform.u_angle, this.angle); - ctx.uniform1f(this.gradShadOP.uniform.u_density, this.ratio); - ctx.uniform1f(this.gradShadOP.uniform.u_max, this.max); - ctx.uniform1f(this.gradShadOP.uniform.u_min, this.min); - ctx.uniform1f(this.gradShadOP.uniform.u_size, this.size); - ctx.uniform1f(this.gradShadOP.uniform.u_intensity, this.intensity); - this.gradShadOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - ctx.drawArrays(ctx.POINTS, 0, (exData.posVec || []).length / 2); + var _a, _b, _c, _d; + ctx.useProgram(this.gradShadOP.program); + this.min = + this.configMin !== null ? this.configMin : (_b = (_a = exData === null || exData === void 0 ? void 0 : exData.minMax) === null || _a === void 0 ? void 0 : _a.min) !== null && _b !== void 0 ? _b : 0; + this.max = + this.configMax !== null ? this.configMax : (_d = (_c = exData === null || exData === void 0 ? void 0 : exData.minMax) === null || _c === void 0 ? void 0 : _c.max) !== null && _d !== void 0 ? _d : 0; + this.gradShadOP.attr[0].data = exData.posVec || []; + this.gradShadOP.attr[1].data = exData.rVec || []; + ctx.uniform2fv(this.gradShadOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); + ctx.uniform2fv(this.gradShadOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); + ctx.uniform1f(this.gradShadOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); + ctx.uniform1f(this.gradShadOP.uniform.u_angle, this.angle); + ctx.uniform1f(this.gradShadOP.uniform.u_density, this.ratio); + ctx.uniform1f(this.gradShadOP.uniform.u_max, this.max); + ctx.uniform1f(this.gradShadOP.uniform.u_min, this.min); + ctx.uniform1f(this.gradShadOP.uniform.u_size, this.size); + ctx.uniform1f(this.gradShadOP.uniform.u_intensity, this.intensity); + this.gradShadOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + ctx.drawArrays(ctx.POINTS, 0, (exData.posVec || []).length / 2); } function renderImage(ctx, imageConfig) { - const { - x = 0, - y = 0, - width = 0, - height = 0 - } = imageConfig; - ctx.useProgram(this.imageShaOP.program); - ctx.uniform2fv(this.imageShaOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); - ctx.uniform2fv(this.imageShaOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); - ctx.uniform1f(this.imageShaOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); - ctx.uniform1f(this.imageShaOP.uniform.u_angle, this.angle); - ctx.uniform1f(this.imageShaOP.uniform.u_density, this.ratio); - this.imageShaOP.attr[0].data = new Float32Array([x, y, x + width, y, x, y + height, x, y + height, x + width, y, x + width, y + height]); - this.imageShaOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - ctx.uniform1i(this.imageShaOP.uniform.u_image, 0); - ctx.activeTexture(this.ctx.TEXTURE0); - ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture); - ctx.drawArrays(ctx.TRIANGLES, 0, 6); + const { x = 0, y = 0, width = 0, height = 0 } = imageConfig; + ctx.useProgram(this.imageShaOP.program); + ctx.uniform2fv(this.imageShaOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); + ctx.uniform2fv(this.imageShaOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); + ctx.uniform1f(this.imageShaOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); + ctx.uniform1f(this.imageShaOP.uniform.u_angle, this.angle); + ctx.uniform1f(this.imageShaOP.uniform.u_density, this.ratio); + this.imageShaOP.attr[0].data = new Float32Array([ + x, + y, + x + width, + y, + x, + y + height, + x, + y + height, + x + width, + y, + x + width, + y + height, + ]); + this.imageShaOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + ctx.uniform1i(this.imageShaOP.uniform.u_image, 0); + ctx.activeTexture(this.ctx.TEXTURE0); + ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture); + ctx.drawArrays(ctx.TRIANGLES, 0, 6); } function renderColorGradiant(ctx) { - ctx.useProgram(this.colorShadOP.program); - ctx.uniform4fv(this.colorShadOP.uniform.u_colorArr, this.gradient.value); - ctx.uniform1f(this.colorShadOP.uniform.u_colorCount, this.gradient.length); - ctx.uniform1fv(this.colorShadOP.uniform.u_offset, new Float32Array(this.gradient.offset)); - ctx.uniform1f(this.colorShadOP.uniform.u_opacity, this.opacity); - this.colorShadOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - ctx.uniform1i(this.colorShadOP.uniform.u_framebuffer, 0); - ctx.activeTexture(ctx.TEXTURE0); - ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); - ctx.drawArrays(ctx.TRIANGLES, 0, 6); + ctx.useProgram(this.colorShadOP.program); + ctx.uniform4fv(this.colorShadOP.uniform.u_colorArr, this.gradient.value); + ctx.uniform1f(this.colorShadOP.uniform.u_colorCount, this.gradient.length); + ctx.uniform1fv(this.colorShadOP.uniform.u_offset, new Float32Array(this.gradient.offset)); + ctx.uniform1f(this.colorShadOP.uniform.u_opacity, this.opacity); + this.colorShadOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + ctx.uniform1i(this.colorShadOP.uniform.u_framebuffer, 0); + ctx.activeTexture(ctx.TEXTURE0); + ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); + ctx.drawArrays(ctx.TRIANGLES, 0, 6); } function imageInstance(url, onLoad, onError) { - const imageIns = new Image(); - imageIns.crossOrigin = 'anonymous'; - imageIns.onload = onLoad; - imageIns.onerror = onError; - imageIns.src = url; - return imageIns; + const imageIns = new Image(); + imageIns.crossOrigin = "anonymous"; + imageIns.onload = onLoad; + imageIns.onerror = onError; + imageIns.src = url; + return imageIns; } class HeatmapRenderer { - constructor(container, config) { - try { - const res = typeof container === 'string' ? document.querySelector(container) : container instanceof HTMLElement ? container : null; - if (!res) { - throw new Error('Context must be either a string or an Element'); - } - const { - clientHeight: height, - clientWidth: width - } = res; - const layer = document.createElement('canvas'); - const ctx = layer.getContext('webgl2', { - premultipliedAlpha: false, - depth: false, - antialias: true, - alpha: true, - preserveDrawingBuffer: false - }); - this.ratio = getPixlRatio(ctx); - ctx.clearColor(0, 0, 0, 0); - ctx.enable(ctx.BLEND); - ctx.blendEquation(ctx.FUNC_ADD); - ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); - ctx.depthMask(true); - layer.setAttribute('height', height * this.ratio); - layer.setAttribute('width', width * this.ratio); - layer.style.height = "".concat(height, "px"); - layer.style.width = "".concat(width, "px"); - layer.style.position = 'absolute'; - res.appendChild(layer); - this.ctx = ctx; - this.width = width; - this.height = height; - this.imageConfig = null; - this.configMin = null; - this.configMax = null; - this.hearmapExData = {}; - this.layer = layer; - this.dom = res; - this.gradShadOP = createGradiantShader(this.ctx, GradShader); - this.colorShadOP = createColorShader(this.ctx, ColorShader); - this.imageShaOP = createImageShader(this.ctx, ImageShader); - this.fbTexObj = ctx.createTexture(); - this.fbo = ctx.createFramebuffer(); - if (!isNullUndefined(config.size)) { - this.setSize(config.size); - } else { - this.size = 20.0; - } - if (!isNullUndefined(config.max)) { - this.setMax(config.max); - } else { - this.configMax = null; - } - if (!isNullUndefined(config.min)) { - this.setMin(config.min); - } else { + constructor(container, config) { + this.ctx = null; + this.ratio = 1; + this.width = 0; + this.height = 0; + this.imageConfig = null; this.configMin = null; - } - if (!isNullUndefined(config.intensity)) { - this.setIntensity(config.intensity); - } else { - this.intensity = 1.0; - } - if (!isNullUndefined(config.translate)) { - this.setTranslate(config.translate); - } else { + this.configMax = null; + this.min = 0; + this.max = 0; + this.hearmapExData = {}; + this.size = 0; + this.zoom = 0; + this.angle = 0; + this.intensity = 0; this.translate = [0, 0]; - } - if (!isNullUndefined(config.zoom)) { - this.setZoom(config.zoom); - } else { - this.zoom = 1.0; - } - if (!isNullUndefined(config.angle)) { - this.setRotationAngle(config.angle); - } else { - this.angle = 0.0; - } - if (!isNullUndefined(config.opacity)) { - this.setOpacity(config.opacity); - } else { - this.opacity = 1.0; - } - this.gradient = gradientMapper(config.gradient); - if (config.backgroundImage && config.backgroundImage.url) { - this.setBackgroundImage(config.backgroundImage); - } - this.heatmapData = []; - this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); - } catch (error) { - console.error(error); - } - } - resize() { - const height = this.dom.clientHeight; - const width = this.dom.clientWidth; - this.layer.setAttribute('height', height * this.ratio); - this.layer.setAttribute('width', width * this.ratio); - this.layer.style.height = "".concat(height, "px"); - this.layer.style.width = "".concat(width, "px"); - this.width = width; - this.height = height; - this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); - /* Perform update */ - this.render(this.hearmapExData); - } - clear() { - this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT); - } - setMax(max) { - if (isNullUndefined(max) || isNotNumber(max)) { - throw new Error('Invalid max: Expected Number'); - } - this.configMax = max; - return this; - } - setMin(min) { - if (isNullUndefined(min) || isNotNumber(min)) { - throw new Error('Invalid min: Expected Number'); - } - this.configMin = min; - return this; - } - setGradient(gradient) { - this.gradient = gradientMapper(gradient); - return this; - } - setTranslate(translate) { - if (translate.constructor !== Array) { - throw new Error('Invalid Translate: Translate has to be of Array type'); - } - if (translate.length !== 2) { - throw new Error('Translate has to be of length 2'); - } - this.translate = translate; - return this; - } - setZoom(zoom) { - if (isNullUndefined(zoom) || isNotNumber(zoom)) { - throw new Error('Invalid zoom: Expected Number'); - } - this.zoom = zoom; - return this; - } - setRotationAngle(angle) { - if (isNullUndefined(angle) || isNotNumber(angle)) { - throw new Error('Invalid Angle: Expected Number'); - } - this.angle = angle; - return this; - } - setSize(size) { - if (isNullUndefined(size) || isNotNumber(size)) { - throw new Error('Invalid Size: Expected Number'); - } - this.size = size; - return this; - } - setIntensity(intensity) { - if (isNullUndefined(intensity) || isNotNumber(intensity)) { - this.intensity = 1.0; // applying default intensity - throw new Error('Invalid Intensity: Expected Number'); - } - if (intensity > 1 || intensity < 0) { - this.intensity = intensity > 1 ? 1 : 0; // Setting bound value - throw new Error('Invalid Intensity value ' + intensity); - } - this.intensity = intensity; - return this; - } - setOpacity(opacity) { - if (isNullUndefined(opacity) || isNotNumber(opacity)) { - throw new Error('Invalid Opacity: Expected Number'); - } - if (opacity > 1 || opacity < 0) { - throw new Error('Invalid Opacity value ' + opacity); - } - this.opacity = opacity; - return this; - } - setBackgroundImage(config) { - const self = this; - if (!config.url) { - return; - } - const maxTextureSize = this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE); - this.imageTexture = this.ctx.createTexture(); - this.type = 'TEXTURE_2D'; - this.imageConfig = null; - this.imgWidth = config.width || this.width; - this.imgHeight = config.height || this.height; - this.imgWidth = this.imgWidth > maxTextureSize ? maxTextureSize : this.imgWidth; - this.imgHeight = this.imgHeight > maxTextureSize ? maxTextureSize : this.imgHeight; - imageInstance(config.url, function onUpdateCallBack() { - self.ctx.activeTexture(self.ctx.TEXTURE0); - self.ctx.bindTexture(self.ctx.TEXTURE_2D, self.imageTexture); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_S, self.ctx.CLAMP_TO_EDGE); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_T, self.ctx.CLAMP_TO_EDGE); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MIN_FILTER, self.ctx.LINEAR); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MAG_FILTER, self.ctx.LINEAR); - self.ctx.texImage2D(self.ctx.TEXTURE_2D, 0, self.ctx.RGBA, this.naturalWidth, this.naturalHeight, 0, self.ctx.RGBA, self.ctx.UNSIGNED_BYTE, this); - self.imageConfig = { - x: config.x || 0, - y: config.y || 0, - height: self.imgHeight, - width: self.imgWidth, - image: this - }; - self.render(); - }, function onErrorCallBack(error) { - throw new Error('Image Load Error', error); - }); - return this; - } - clearData() { - this.heatmapData = []; - this.hearmapExData = {}; - this.render(); - } - addData(data, transIntactFlag) { - const self = this; - for (let i = 0; i < data.length; i++) { - if (transIntactFlag) { - transCoOr.call(self, data[i]); - } - this.heatmapData.push(data[i]); - } - this.renderData(this.heatmapData); - return this; - } - renderData(data) { - if (data.constructor !== Array) { - throw new Error('Expected Array type'); - } - this.hearmapExData = extractData(data, this); - this.heatmapData = data; - this.render(); - return this; - } - render() { - renderExec.call(this); - } - projection(data) { - // Pre-compute constants and repetitive calculations - const zoomFactor = this.zoom || 0.1; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - const translateX = this.translate[0]; - const translateY = this.translate[1]; - const angle = this.angle; - const aspect = this.width / this.height; - - // Calculate the adjusted positions - let posX = (data.x + translateX - halfWidth) / (halfWidth * zoomFactor); - let posY = (data.y + translateY - halfHeight) / (halfHeight * zoomFactor); - posX *= aspect; - - // Rotate the point if there's an angle - if (angle !== 0.0) { - const cosAngle = Math.cos(-angle); - const sinAngle = Math.sin(-angle); - const xNew = cosAngle * posX - sinAngle * posY; - posY = sinAngle * posX + cosAngle * posY; - posX = xNew; + this.opacity = 0; + this.gradient = null; + this.imageTexture = null; + this.pLen = undefined; + this.buffer = undefined; + this.buffer2 = undefined; + this.imgWidth = 0; + this.imgHeight = 0; + this.heatmapData = []; + this.type = ""; + try { + const res = typeof container === "string" + ? document.querySelector(container) + : container instanceof HTMLElement + ? container + : null; + if (!res) { + throw new Error("Context must be either a string or an Element"); + } + const { clientHeight: height, clientWidth: width } = res; + const layer = document.createElement("canvas"); + const ctx = layer.getContext("webgl2", { + premultipliedAlpha: false, + depth: false, + antialias: true, + alpha: true, + preserveDrawingBuffer: false, + }); + this.ratio = getPixelRatio(ctx); + ctx.clearColor(0, 0, 0, 0); + ctx.enable(ctx.BLEND); + ctx.blendEquation(ctx.FUNC_ADD); + ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); + ctx.depthMask(true); + layer.setAttribute("height", (height * this.ratio).toString()); + layer.setAttribute("width", (width * this.ratio).toString()); + layer.style.height = `${height}px`; + layer.style.width = `${width}px`; + layer.style.position = "absolute"; + res.appendChild(layer); + this.ctx = ctx; + this.width = width; + this.height = height; + this.imageConfig = null; + this.configMin = null; + this.configMax = null; + this.hearmapExData = {}; + this.layer = layer; + this.dom = res; + this.gradShadOP = createGradiantShader(this.ctx, GradShader); + this.colorShadOP = createColorShader(this.ctx, ColorShader); + this.imageShaOP = createImageShader(this.ctx, ImageShader); + this.fbTexObj = ctx.createTexture(); + this.fbo = ctx.createFramebuffer(); + if (!isNullUndefined(config.size)) { + this.setSize(config.size); + } + else { + this.size = 20.0; + } + if (!isNullUndefined(config.max)) { + this.setMax(config.max); + } + else { + this.configMax = null; + } + if (!isNullUndefined(config.min)) { + this.setMin(config.min); + } + else { + this.configMin = null; + } + if (!isNullUndefined(config.intensity)) { + this.setIntensity(config.intensity); + } + else { + this.intensity = 1.0; + } + if (!isNullUndefined(config.translate)) { + this.setTranslate(config.translate); + } + else { + this.translate = [0, 0]; + } + if (!isNullUndefined(config.zoom)) { + this.setZoom(config.zoom); + } + else { + this.zoom = 1.0; + } + if (!isNullUndefined(config.angle)) { + this.setRotationAngle(config.angle); + } + else { + this.angle = 0.0; + } + if (!isNullUndefined(config.opacity)) { + this.setOpacity(config.opacity); + } + else { + this.opacity = 1.0; + } + this.gradient = gradientMapper(config.gradient); + if (config.backgroundImage && config.backgroundImage.url) { + this.setBackgroundImage(config.backgroundImage); + } + this.heatmapData = []; + this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + } + catch (error) { + console.error(error); + } + } + resize() { + const height = this.dom.clientHeight; + const width = this.dom.clientWidth; + this.layer.setAttribute("height", (height * this.ratio).toString()); + this.layer.setAttribute("width", (width * this.ratio).toString()); + this.layer.style.height = `${height}px`; + this.layer.style.width = `${width}px`; + this.width = width; + this.height = height; + this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + /* Perform update */ + this.render(); + } + clear() { + this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT); + } + setMax(max) { + if (isNullUndefined(max) || isNotNumber(max)) { + throw new Error("Invalid max: Expected Number"); + } + this.configMax = max; + return this; + } + setMin(min) { + if (isNullUndefined(min) || isNotNumber(min)) { + throw new Error("Invalid min: Expected Number"); + } + this.configMin = min; + return this; + } + setGradient(gradient) { + this.gradient = gradientMapper(gradient); + return this; + } + setTranslate(translate) { + if (translate.constructor !== Array) { + throw new Error("Invalid Translate: Translate has to be of Array type"); + } + if (translate.length !== 2) { + throw new Error("Translate has to be of length 2"); + } + this.translate = translate; + return this; + } + setZoom(zoom) { + if (isNullUndefined(zoom) || isNotNumber(zoom)) { + throw new Error("Invalid zoom: Expected Number"); + } + this.zoom = zoom; + return this; + } + setRotationAngle(angle) { + if (isNullUndefined(angle) || isNotNumber(angle)) { + throw new Error("Invalid Angle: Expected Number"); + } + this.angle = angle; + return this; + } + setSize(size) { + if (isNullUndefined(size) || isNotNumber(size)) { + throw new Error("Invalid Size: Expected Number"); + } + this.size = size; + return this; + } + setIntensity(intensity) { + if (isNullUndefined(intensity) || isNotNumber(intensity)) { + this.intensity = 1.0; // applying default intensity + throw new Error("Invalid Intensity: Expected Number"); + } + if (intensity > 1 || intensity < 0) { + this.intensity = intensity > 1 ? 1 : 0; // Setting bound value + throw new Error("Invalid Intensity value " + intensity); + } + this.intensity = intensity; + return this; + } + setOpacity(opacity) { + if (isNullUndefined(opacity) || isNotNumber(opacity)) { + throw new Error("Invalid Opacity: Expected Number"); + } + if (opacity > 1 || opacity < 0) { + throw new Error("Invalid Opacity value " + opacity); + } + this.opacity = opacity; + return this; + } + setBackgroundImage(config) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + if (!config.url) { + return; + } + const maxTextureSize = this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE); + this.imageTexture = this.ctx.createTexture(); + this.type = "TEXTURE_2D"; + this.imageConfig = null; + this.imgWidth = config.width || this.width; + this.imgHeight = config.height || this.height; + this.imgWidth = + this.imgWidth > maxTextureSize ? maxTextureSize : this.imgWidth; + this.imgHeight = + this.imgHeight > maxTextureSize ? maxTextureSize : this.imgHeight; + imageInstance(config.url, function onUpdateCallBack() { + self.ctx.activeTexture(self.ctx.TEXTURE0); + self.ctx.bindTexture(self.ctx.TEXTURE_2D, self.imageTexture); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_S, self.ctx.CLAMP_TO_EDGE); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_T, self.ctx.CLAMP_TO_EDGE); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MIN_FILTER, self.ctx.LINEAR); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MAG_FILTER, self.ctx.LINEAR); + self.ctx.texImage2D(self.ctx.TEXTURE_2D, 0, self.ctx.RGBA, this.naturalWidth, this.naturalHeight, 0, self.ctx.RGBA, self.ctx.UNSIGNED_BYTE, this); + self.imageConfig = { + x: config.x || 0, + y: config.y || 0, + height: self.imgHeight, + width: self.imgWidth, + image: this, + }; + self.render(); + }, function onErrorCallBack(error) { + throw new Error(`Image Load Error, ${error}`); + }); + return this; + } + clearData() { + this.heatmapData = []; + this.hearmapExData = {}; + this.render(); } - posX *= 1.0 / aspect; + addData(data, transIntactFlag) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + for (let i = 0; i < data.length; i++) { + if (transIntactFlag) { + transCoOr.call(self, data[i]); + } + this.heatmapData.push(data[i]); + } + this.renderData(this.heatmapData); + return this; + } + renderData(data) { + if (data.constructor !== Array) { + throw new Error("Expected Array type"); + } + this.hearmapExData = extractData(data, this); + this.heatmapData = data; + this.render(); + return this; + } + render() { + renderExec.call(this); + } + projection(data) { + // Pre-compute constants and repetitive calculations + const zoomFactor = this.zoom || 0.1; + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + const translateX = this.translate[0]; + const translateY = this.translate[1]; + const angle = this.angle; + const aspect = this.width / this.height; + // Calculate the adjusted positions + let posX = (data.x + translateX - halfWidth) / (halfWidth * zoomFactor); + let posY = (data.y + translateY - halfHeight) / (halfHeight * zoomFactor); + posX *= aspect; + // Rotate the point if there's an angle + if (angle !== 0.0) { + const cosAngle = Math.cos(-angle); + const sinAngle = Math.sin(-angle); + const xNew = cosAngle * posX - sinAngle * posY; + posY = sinAngle * posX + cosAngle * posY; + posX = xNew; + } + posX *= 1.0 / aspect; + // Scale back and adjust the position + posX = posX * halfWidth + halfWidth; + posY = posY * halfHeight + halfHeight; + return { x: posX, y: posY }; + } +} - // Scale back and adjust the position - posX = posX * halfWidth + halfWidth; - posY = posY * halfHeight + halfHeight; - return { - x: posX, - y: posY - }; - } +// Internal class that encapsulates private properties and methods +class Heatmap { + constructor(context, config) { + this.renderer = new HeatmapRenderer(context, config); + this.ctx = this.renderer.ctx; + this.ratio = this.renderer.ratio; + this.width = this.renderer.width; + this.height = this.renderer.height; + this.min = this.renderer.min; + this.max = this.renderer.max; + this.size = this.renderer.size; + this.zoom = this.renderer.zoom; + this.angle = this.renderer.angle; + this.intensity = this.renderer.intensity; + this.translate = this.renderer.translate; + this.opacity = this.renderer.opacity; + this.gradient = this.renderer.gradient; + this.imageConfig = this.renderer.imageConfig; + } + /** + * Set the maximum data value for relative gradient calculations + * @param max - number + * @returns instance + */ + setMax(max) { + return this.renderer.setMax(max); + } + /** + * Set the minimum data value for relative gradient calculations + * @param min - number + * @returns instance + */ + setMin(min) { + return this.renderer.setMin(min); + } + /** + * Accepts array of objects with color value and offset + * @param gradient - Color Gradient + * @returns instance + */ + setGradient(gradient) { + return this.renderer.setGradient(gradient); + } + /** + * Set the translate transformation on the canvas + * @param translate - Accepts array [x, y] + * @returns instance + */ + setTranslate(translate) { + return this.renderer.setTranslate(translate); + } + /** + * Set the zoom transformation on the canvas + * @param zoom - Accepts float value + * @returns instance + */ + setZoom(zoom) { + return this.renderer.setZoom(zoom); + } + /** + * Set the rotation transformation on the canvas + * @param angle - Accepts angle in radians + * @returns instance + */ + setRotationAngle(angle) { + return this.renderer.setRotationAngle(angle); + } + /** + * Set the point radius + * @param size - Accepts float value + * @returns instance + */ + setSize(size) { + return this.renderer.setSize(size); + } + /** + * Set the intensity factor + * @param intensity - Accepts float value + * @returns instance + */ + setIntensity(intensity) { + return this.renderer.setIntensity(intensity); + } + /** + * Set the opacity factor + * @param opacity - The opacity factor. + * @returns instance + */ + setOpacity(opacity) { + return this.renderer.setOpacity(opacity); + } + /** + * Set the background image + * @param config - Accepts Object with { Url, height, width, x, and y} properties + * @returns instance + */ + setBackgroundImage(config) { + return this.renderer.setBackgroundImage(config); + } + /** + * After adding data points, need to invoke .render() method to update the heatmap + * @param data - The data points with 'x', 'y' and 'value' + * @param transIntactFlag - Flag indicating whether to apply existing heatmap transformations on the newly added data points + * @returns instance + */ + addData(data, transIntactFlag) { + return this.renderer.addData(data, transIntactFlag); + } + /** + * @param data - Accepts an array of data points with 'x', 'y' and 'value' + * @returns instance + */ + renderData(data) { + return this.renderer.renderData(data); + } + /** + * Method to re-render the heatmap. This method needs to be invoked as and when configurations get changed + */ + render() { + this.renderer.render(); + } + /** + * Get projected co-ordinates relative to the heatmap layer + * @param data - The data point to project. + * @returns projected data point. + */ + projection(data) { + return this.renderer.projection(data); + } + /** + * Clears canvas + */ + clear() { + this.renderer.clear(); + } } -function Heatmap(context) { - let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - return new HeatmapRenderer(context, config); +function main (context, config) { + return new Heatmap(context, config); } -export { Heatmap as default }; +export { main as default }; diff --git a/dist/visualHeatmap.esm.min.js b/dist/visualHeatmap.esm.min.js index 05442e0..dde8f79 100644 --- a/dist/visualHeatmap.esm.min.js +++ b/dist/visualHeatmap.esm.min.js @@ -3,4 +3,4 @@ * (c) 2024 Narayana Swamy (narayanaswamy14@gmail.com) * @license BSD-3-Clause */ -const t={vertex:"#version 300 es\n\t\t\t\tin vec2 a_position;\n\t\t\t\tin float a_intensity;\n\t\t\t\tuniform float u_size;\n\t\t\t\tuniform vec2 u_resolution;\n\t\t\t\tuniform vec2 u_translate; \n\t\t\t\tuniform float u_zoom; \n\t\t\t\tuniform float u_angle; \n\t\t\t\tuniform float u_density;\n\t\t\t\tout float v_i;\n\n\t\t\t\tvec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 rotationMat = mat2(c, -s, s, c); \n\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\treturn scaleMatInv * rotationMat * scaleMat * v;\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\tfloat zoomFactor = max(u_zoom, 0.1);\n\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle, u_resolution.x / u_resolution.y);\n\t\t\t\t\t}\n\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\tgl_PointSize = u_size * u_density;\n\t\t\t\t\tv_i = a_intensity;\n\t\t\t\t}",fragment:"#version 300 es\n\t\t\t\tprecision mediump float;\n\t\t\t\tuniform float u_max;\n\t\t\t\tuniform float u_min;\n\t\t\t\tuniform float u_intensity;\n\t\t\t\tin float v_i;\n\t\t\t\tout vec4 fragColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat r = 0.0; \n\t\t\t\t\tvec2 cxy = 2.0 * gl_PointCoord - 1.0;\n\t\t\t\t\tr = dot(cxy, cxy);\n\t\t\t\t\tfloat deno = max(u_max - u_min, 1.0);\n\t\t\t\t\tif(r <= 1.0) {\n\t\t\t\t\t\tfragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r)));\n\t\t\t\t\t}\n\t\t\t\t}"},e={vertex:"#version 300 es\n\t\t\t\tprecision highp float;\n\t\t\t\tin vec2 a_texCoord;\n\t\t\t\tout vec2 v_texCoord;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 clipSpace = a_texCoord * 2.0 - 1.0;\n\t\t\t\t\tgl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\t\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t\t}\n\t",fragment:"#version 300 es\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t\tin vec2 v_texCoord;\n\t\t\t\t\tout vec4 fragColor;\n\t\t\t\t\tuniform sampler2D u_framebuffer;\n\t\t\t\t\tuniform vec4 u_colorArr[20];\n\t\t\t\t\tuniform float u_colorCount;\n\t\t\t\t\tuniform float u_opacity;\n\t\t\t\t\tuniform float u_offset[20];\n\n\t\t\t\t\tfloat remap ( float minval, float maxval, float curval ) {\n\t\t\t\t\t\treturn ( curval - minval ) / ( maxval - minval );\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid main() {\n\t\t\t\t\t\tfloat alpha = texture(u_framebuffer, v_texCoord.xy).a;\n\t\t\t\t\t\tif (alpha > 0.0 && alpha <= 1.0) {\n\t\t\t\t\t\t\tvec4 color_;\n\n\t\t\t\t\t\t\tif (alpha <= u_offset[0]) {\n\t\t\t\t\t\t\t\tcolor_ = u_colorArr[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= 20; ++i) {\n\t\t\t\t\t\t\t\t\tif (alpha <= u_offset[i]) {\n\t\t\t\t\t\t\t\t\t\tcolor_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) );\n\t\t\t\t\t\t\t\t\t\tcolor_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha ));\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcolor_ = color_ * u_opacity;\n\t\t\t\t\t\t\tif (color_.a < 0.0) {\n\t\t\t\t\t\t\t\tcolor_.a = 0.0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfragColor = color_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t"},i={vertex:"#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n uniform vec2 u_resolution;\n\t\t\t\t\tuniform vec2 u_translate; \n\t\t\t\t\tuniform float u_zoom; \n\t\t\t\t\tuniform float u_angle; \n\t\t\t\t\tuniform float u_density;\n out vec2 v_texCoord;\n\n vec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c);\n\t\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\treturn scaleMatInv * m * scaleMat * v;\n\t\t\t\t\t}\n\n void main() {\n \tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n \tzeroToOne.y = 1.0 - zeroToOne.y;\n\t\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\t\tfloat zoomFactor = u_zoom;\n\t\t\t\t\t\tif (zoomFactor == 0.0) {\n\t\t\t\t\t\t\tzoomFactor = 0.1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\t\tv_texCoord = a_texCoord;\n }\n \t\t",fragment:"#version 300 es\n precision mediump float;\n uniform sampler2D u_image;\n in vec2 v_texCoord;\n out vec4 fragColor;\n void main() {\n fragColor = texture(u_image, v_texCoord);\n }\n "};function r(t,e,i){var r=t.createShader(t[e]);if(t.shaderSource(r,i),t.compileShader(r),!t.getShaderParameter(r,t.COMPILE_STATUS)){var o=t.getShaderInfoLog(r);throw t.deleteShader(r),new Error("*** Error compiling shader '"+r+"':"+o)}return r}function o(t,e){var i=r(t,"VERTEX_SHADER",e.vertex),o=r(t,"FRAGMENT_SHADER",e.fragment),a=t.createProgram();if(t.attachShader(a,i),t.attachShader(a,o),t.linkProgram(a),t.getProgramParameter(a,t.LINK_STATUS))return a;var n=t.getProgramInfoLog(a);throw t.deleteProgram(a),new Error("Error in program linking:"+n)}function a(t){return null==t}function n(t){return"number"!=typeof t}function s(t){if(!Array.isArray(t)||t.length<2)throw new Error("Invalid gradient: Expected an array with at least 2 elements.");if(!function(t){for(let e=0;e1||t<0)throw this.intensity=t>1?1:0,new Error("Invalid Intensity value "+t);return this.intensity=t,this}setOpacity(t){if(a(t)||n(t))throw new Error("Invalid Opacity: Expected Number");if(t>1||t<0)throw new Error("Invalid Opacity value "+t);return this.opacity=t,this}setBackgroundImage(t){const e=this;if(!t.url)return;const i=this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE);return this.imageTexture=this.ctx.createTexture(),this.type="TEXTURE_2D",this.imageConfig=null,this.imgWidth=t.width||this.width,this.imgHeight=t.height||this.height,this.imgWidth=this.imgWidth>i?i:this.imgWidth,this.imgHeight=this.imgHeight>i?i:this.imgHeight,function(t,e,i){const r=new Image;r.crossOrigin="anonymous",r.onload=e,r.onerror=i,r.src=t}(t.url,(function(){e.ctx.activeTexture(e.ctx.TEXTURE0),e.ctx.bindTexture(e.ctx.TEXTURE_2D,e.imageTexture),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_S,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_T,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MIN_FILTER,e.ctx.LINEAR),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MAG_FILTER,e.ctx.LINEAR),e.ctx.texImage2D(e.ctx.TEXTURE_2D,0,e.ctx.RGBA,this.naturalWidth,this.naturalHeight,0,e.ctx.RGBA,e.ctx.UNSIGNED_BYTE,this),e.imageConfig={x:t.x||0,y:t.y||0,height:e.imgHeight,width:e.imgWidth,image:this},e.render()}),(function(t){throw new Error("Image Load Error",t)})),this}clearData(){this.heatmapData=[],this.hearmapExData={},this.render()}addData(t,e){const i=this;for(let r=0;rt[e].value&&(a.min=t[e].value),a.max1&&void 0!==arguments[1]?arguments[1]:{})}export{_ as default}; \ No newline at end of file +const t={vertex:"#version 300 es\n\t\t\t\tin vec2 a_position;\n\t\t\t\tin float a_intensity;\n\t\t\t\tuniform float u_size;\n\t\t\t\tuniform vec2 u_resolution;\n\t\t\t\tuniform vec2 u_translate; \n\t\t\t\tuniform float u_zoom; \n\t\t\t\tuniform float u_angle; \n\t\t\t\tuniform float u_density;\n\t\t\t\tout float v_i;\n\n\t\t\t\tvec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 rotationMat = mat2(c, -s, s, c); \n\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\treturn scaleMatInv * rotationMat * scaleMat * v;\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\tfloat zoomFactor = max(u_zoom, 0.1);\n\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle, u_resolution.x / u_resolution.y);\n\t\t\t\t\t}\n\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\tgl_PointSize = u_size * u_density;\n\t\t\t\t\tv_i = a_intensity;\n\t\t\t\t}",fragment:"#version 300 es\n\t\t\t\tprecision mediump float;\n\t\t\t\tuniform float u_max;\n\t\t\t\tuniform float u_min;\n\t\t\t\tuniform float u_intensity;\n\t\t\t\tin float v_i;\n\t\t\t\tout vec4 fragColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat r = 0.0; \n\t\t\t\t\tvec2 cxy = 2.0 * gl_PointCoord - 1.0;\n\t\t\t\t\tr = dot(cxy, cxy);\n\t\t\t\t\tfloat deno = max(u_max - u_min, 1.0);\n\t\t\t\t\tif(r <= 1.0) {\n\t\t\t\t\t\tfragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r)));\n\t\t\t\t\t}\n\t\t\t\t}"},e={vertex:"#version 300 es\n\t\t\t\tprecision highp float;\n\t\t\t\tin vec2 a_texCoord;\n\t\t\t\tout vec2 v_texCoord;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 clipSpace = a_texCoord * 2.0 - 1.0;\n\t\t\t\t\tgl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\t\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t\t}\n\t",fragment:"#version 300 es\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t\tin vec2 v_texCoord;\n\t\t\t\t\tout vec4 fragColor;\n\t\t\t\t\tuniform sampler2D u_framebuffer;\n\t\t\t\t\tuniform vec4 u_colorArr[20];\n\t\t\t\t\tuniform float u_colorCount;\n\t\t\t\t\tuniform float u_opacity;\n\t\t\t\t\tuniform float u_offset[20];\n\n\t\t\t\t\tfloat remap ( float minval, float maxval, float curval ) {\n\t\t\t\t\t\treturn ( curval - minval ) / ( maxval - minval );\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid main() {\n\t\t\t\t\t\tfloat alpha = texture(u_framebuffer, v_texCoord.xy).a;\n\t\t\t\t\t\tif (alpha > 0.0 && alpha <= 1.0) {\n\t\t\t\t\t\t\tvec4 color_;\n\n\t\t\t\t\t\t\tif (alpha <= u_offset[0]) {\n\t\t\t\t\t\t\t\tcolor_ = u_colorArr[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= 20; ++i) {\n\t\t\t\t\t\t\t\t\tif (alpha <= u_offset[i]) {\n\t\t\t\t\t\t\t\t\t\tcolor_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) );\n\t\t\t\t\t\t\t\t\t\tcolor_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha ));\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcolor_ = color_ * u_opacity;\n\t\t\t\t\t\t\tif (color_.a < 0.0) {\n\t\t\t\t\t\t\t\tcolor_.a = 0.0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfragColor = color_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t"},r={vertex:"#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n uniform vec2 u_resolution;\n\t\t\t\t\tuniform vec2 u_translate; \n\t\t\t\t\tuniform float u_zoom; \n\t\t\t\t\tuniform float u_angle; \n\t\t\t\t\tuniform float u_density;\n out vec2 v_texCoord;\n\n vec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c);\n\t\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\treturn scaleMatInv * m * scaleMat * v;\n\t\t\t\t\t}\n\n void main() {\n \tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n \tzeroToOne.y = 1.0 - zeroToOne.y;\n\t\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\t\tfloat zoomFactor = u_zoom;\n\t\t\t\t\t\tif (zoomFactor == 0.0) {\n\t\t\t\t\t\t\tzoomFactor = 0.1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\t\tv_texCoord = a_texCoord;\n }\n \t\t",fragment:"#version 300 es\n precision mediump float;\n uniform sampler2D u_image;\n in vec2 v_texCoord;\n out vec4 fragColor;\n void main() {\n fragColor = texture(u_image, v_texCoord);\n }\n "};function i(t,e,r){const i=t.createShader(t[e]);if(!i)throw new Error("Failed to create shader.");t.shaderSource(i,r),t.compileShader(i);if(!t.getShaderParameter(i,t.COMPILE_STATUS)){const e=t.getShaderInfoLog(i);throw t.deleteShader(i),new Error("*** Error compiling shader '"+i+"':"+e)}return i}function n(t,e){const r=i(t,"VERTEX_SHADER",e.vertex),n=i(t,"FRAGMENT_SHADER",e.fragment),o=t.createProgram();if(!o)throw new Error("Failed to create program.");t.attachShader(o,r),t.attachShader(o,n),t.linkProgram(o);if(t.getProgramParameter(o,t.LINK_STATUS))return o;{const e=t.getProgramInfoLog(o);throw t.deleteProgram(o),new Error("Error in program linking:"+e)}}function o(t){return null==t}function a(t){return"number"!=typeof t}function s(t){if(!Array.isArray(t)||t.length<2)throw new Error("Invalid gradient: Expected an array with at least 2 elements.");if(!function(t){for(let e=0;e1||t<0)throw this.intensity=t>1?1:0,new Error("Invalid Intensity value "+t);return this.intensity=t,this}setOpacity(t){if(o(t)||a(t))throw new Error("Invalid Opacity: Expected Number");if(t>1||t<0)throw new Error("Invalid Opacity value "+t);return this.opacity=t,this}setBackgroundImage(t){const e=this;if(!t.url)return;const r=this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE);return this.imageTexture=this.ctx.createTexture(),this.type="TEXTURE_2D",this.imageConfig=null,this.imgWidth=t.width||this.width,this.imgHeight=t.height||this.height,this.imgWidth=this.imgWidth>r?r:this.imgWidth,this.imgHeight=this.imgHeight>r?r:this.imgHeight,function(t,e,r){const i=new Image;i.crossOrigin="anonymous",i.onload=e,i.onerror=r,i.src=t}(t.url,(function(){e.ctx.activeTexture(e.ctx.TEXTURE0),e.ctx.bindTexture(e.ctx.TEXTURE_2D,e.imageTexture),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_S,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_T,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MIN_FILTER,e.ctx.LINEAR),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MAG_FILTER,e.ctx.LINEAR),e.ctx.texImage2D(e.ctx.TEXTURE_2D,0,e.ctx.RGBA,this.naturalWidth,this.naturalHeight,0,e.ctx.RGBA,e.ctx.UNSIGNED_BYTE,this),e.imageConfig={x:t.x||0,y:t.y||0,height:e.imgHeight,width:e.imgWidth,image:this},e.render()}),(function(t){throw new Error(`Image Load Error, ${t}`)})),this}clearData(){this.heatmapData=[],this.hearmapExData={},this.render()}addData(t,e){const r=this;for(let i=0;it[e].value&&(o.min=t[e].value),o.max 0.0 && alpha <= 1.0) {\n\t\t\t\t\t\t\tvec4 color_;\n\n\t\t\t\t\t\t\tif (alpha <= u_offset[0]) {\n\t\t\t\t\t\t\t\tcolor_ = u_colorArr[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= 20; ++i) {\n\t\t\t\t\t\t\t\t\tif (alpha <= u_offset[i]) {\n\t\t\t\t\t\t\t\t\t\tcolor_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) );\n\t\t\t\t\t\t\t\t\t\tcolor_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha ));\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcolor_ = color_ * u_opacity;\n\t\t\t\t\t\t\tif (color_.a < 0.0) {\n\t\t\t\t\t\t\t\tcolor_.a = 0.0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfragColor = color_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t" + vertex: `#version 300 es + precision highp float; + in vec2 a_texCoord; + out vec2 v_texCoord; + void main() { + vec2 clipSpace = a_texCoord * 2.0 - 1.0; + gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); + v_texCoord = a_texCoord; + } + `, + fragment: `#version 300 es + precision mediump float; + in vec2 v_texCoord; + out vec4 fragColor; + uniform sampler2D u_framebuffer; + uniform vec4 u_colorArr[20]; + uniform float u_colorCount; + uniform float u_opacity; + uniform float u_offset[20]; + + float remap ( float minval, float maxval, float curval ) { + return ( curval - minval ) / ( maxval - minval ); + } + + void main() { + float alpha = texture(u_framebuffer, v_texCoord.xy).a; + if (alpha > 0.0 && alpha <= 1.0) { + vec4 color_; + + if (alpha <= u_offset[0]) { + color_ = u_colorArr[0]; + } else { + for (int i = 1; i <= 20; ++i) { + if (alpha <= u_offset[i]) { + color_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) ); + color_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha )); + + break; + } + } + } + + color_ = color_ * u_opacity; + if (color_.a < 0.0) { + color_.a = 0.0; + } + fragColor = color_; + } else { + fragColor = vec4(0.0, 0.0, 0.0, 0.0); + } + } + `, }; const ImageShader = { - vertex: "#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n uniform vec2 u_resolution;\n\t\t\t\t\tuniform vec2 u_translate; \n\t\t\t\t\tuniform float u_zoom; \n\t\t\t\t\tuniform float u_angle; \n\t\t\t\t\tuniform float u_density;\n out vec2 v_texCoord;\n\n vec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c);\n\t\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\treturn scaleMatInv * m * scaleMat * v;\n\t\t\t\t\t}\n\n void main() {\n \tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n \tzeroToOne.y = 1.0 - zeroToOne.y;\n\t\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\t\tfloat zoomFactor = u_zoom;\n\t\t\t\t\t\tif (zoomFactor == 0.0) {\n\t\t\t\t\t\t\tzoomFactor = 0.1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\t\tv_texCoord = a_texCoord;\n }\n \t\t", - fragment: "#version 300 es\n precision mediump float;\n uniform sampler2D u_image;\n in vec2 v_texCoord;\n out vec4 fragColor;\n void main() {\n fragColor = texture(u_image, v_texCoord);\n }\n " + vertex: `#version 300 es + precision highp float; + in vec2 a_position; + in vec2 a_texCoord; + uniform vec2 u_resolution; + uniform vec2 u_translate; + uniform float u_zoom; + uniform float u_angle; + uniform float u_density; + out vec2 v_texCoord; + + vec2 rotation(vec2 v, float a, float aspect) { + float s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c); + mat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0); + mat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0); + return scaleMatInv * m * scaleMat * v; + } + + void main() { + vec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution); + zeroToOne.y = 1.0 - zeroToOne.y; + vec2 zeroToTwo = zeroToOne * 2.0 - 1.0; + float zoomFactor = u_zoom; + if (zoomFactor == 0.0) { + zoomFactor = 0.1; + } + zeroToTwo = zeroToTwo / zoomFactor; + if (u_angle != 0.0) { + zeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y); + } + + gl_Position = vec4(zeroToTwo , 0, 1); + v_texCoord = a_texCoord; + } + `, + fragment: `#version 300 es + precision mediump float; + uniform sampler2D u_image; + in vec2 v_texCoord; + out vec4 fragColor; + void main() { + fragColor = texture(u_image, v_texCoord); + } + `, }; function createShader(ctx, type, src) { - var shader = ctx.createShader(ctx[type]); - ctx.shaderSource(shader, src); - ctx.compileShader(shader); - var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); - if (!compiled) { - var lastError = ctx.getShaderInfoLog(shader); - ctx.deleteShader(shader); - throw new Error("*** Error compiling shader '" + shader + "':" + lastError); - } - return shader; + const shader = ctx.createShader(ctx[type]); + if (!shader) { + throw new Error("Failed to create shader."); + } + ctx.shaderSource(shader, src); + ctx.compileShader(shader); + const compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); + if (!compiled) { + const lastError = ctx.getShaderInfoLog(shader); + ctx.deleteShader(shader); + throw new Error("*** Error compiling shader '" + shader + "':" + lastError); + } + return shader; } function createProgram(ctx, shader) { - var vshader = createShader(ctx, 'VERTEX_SHADER', shader.vertex); - var fshader = createShader(ctx, 'FRAGMENT_SHADER', shader.fragment); - var program = ctx.createProgram(); - ctx.attachShader(program, vshader); - ctx.attachShader(program, fshader); - ctx.linkProgram(program); - var linked = ctx.getProgramParameter(program, ctx.LINK_STATUS); - if (!linked) { - var lastError = ctx.getProgramInfoLog(program); - ctx.deleteProgram(program); - throw new Error('Error in program linking:' + lastError); - } else { - return program; - } + const vshader = createShader(ctx, "VERTEX_SHADER", shader.vertex); + const fshader = createShader(ctx, "FRAGMENT_SHADER", shader.fragment); + const program = ctx.createProgram(); + if (!program) { + throw new Error("Failed to create program."); + } + ctx.attachShader(program, vshader); + ctx.attachShader(program, fshader); + ctx.linkProgram(program); + const linked = ctx.getProgramParameter(program, ctx.LINK_STATUS); + if (!linked) { + const lastError = ctx.getProgramInfoLog(program); + ctx.deleteProgram(program); + throw new Error("Error in program linking:" + lastError); + } + else { + return program; + } } const createImageShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_position'), - data: new Float32Array([]) - }, { - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_texCoord'), - data: new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]) - }], - uniform: { - u_resolution: ctx.getUniformLocation(program, 'u_resolution'), - u_image: ctx.getUniformLocation(program, 'u_image'), - u_translate: ctx.getUniformLocation(program, 'u_translate'), - u_zoom: ctx.getUniformLocation(program, 'u_zoom'), - u_angle: ctx.getUniformLocation(program, 'u_angle'), - u_density: ctx.getUniformLocation(program, 'u_density') - } - }; + const program = createProgram(ctx, shader); + const positionBuffer = ctx.createBuffer(); + if (!positionBuffer) { + throw new Error("Failed to create position buffer."); + } + const texCoordBuffer = ctx.createBuffer(); + if (!texCoordBuffer) { + throw new Error("Failed to create texture coordinate buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: positionBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_position"), + data: new Float32Array([]), + }, + { + bufferType: ctx.ARRAY_BUFFER, + buffer: texCoordBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_texCoord"), + data: new Float32Array([ + 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, + ]), + }, + ], + uniform: { + u_resolution: ctx.getUniformLocation(program, "u_resolution"), + u_image: ctx.getUniformLocation(program, "u_image"), + u_translate: ctx.getUniformLocation(program, "u_translate"), + u_zoom: ctx.getUniformLocation(program, "u_zoom"), + u_angle: ctx.getUniformLocation(program, "u_angle"), + u_density: ctx.getUniformLocation(program, "u_density"), + }, + }; }; const createGradiantShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_position'), - data: new Float32Array([]) - }, { - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 1, - attribute: ctx.getAttribLocation(program, 'a_intensity'), - data: new Float32Array([]) - }], - uniform: { - u_resolution: ctx.getUniformLocation(program, 'u_resolution'), - u_max: ctx.getUniformLocation(program, 'u_max'), - u_min: ctx.getUniformLocation(program, 'u_min'), - u_size: ctx.getUniformLocation(program, 'u_size'), - u_intensity: ctx.getUniformLocation(program, 'u_intensity'), - u_translate: ctx.getUniformLocation(program, 'u_translate'), - u_zoom: ctx.getUniformLocation(program, 'u_zoom'), - u_angle: ctx.getUniformLocation(program, 'u_angle'), - u_density: ctx.getUniformLocation(program, 'u_density') - } - }; + const program = createProgram(ctx, shader); + const positionBuffer = ctx.createBuffer(); + if (!positionBuffer) { + throw new Error("Failed to create position buffer."); + } + const intensityBuffer = ctx.createBuffer(); + if (!intensityBuffer) { + throw new Error("Failed to create intensity buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: positionBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_position"), + data: new Float32Array([]), + }, + { + bufferType: ctx.ARRAY_BUFFER, + buffer: intensityBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 1, + attribute: ctx.getAttribLocation(program, "a_intensity"), + data: new Float32Array([]), + }, + ], + uniform: { + u_resolution: ctx.getUniformLocation(program, "u_resolution"), + u_max: ctx.getUniformLocation(program, "u_max"), + u_min: ctx.getUniformLocation(program, "u_min"), + u_size: ctx.getUniformLocation(program, "u_size"), + u_intensity: ctx.getUniformLocation(program, "u_intensity"), + u_translate: ctx.getUniformLocation(program, "u_translate"), + u_zoom: ctx.getUniformLocation(program, "u_zoom"), + u_angle: ctx.getUniformLocation(program, "u_angle"), + u_density: ctx.getUniformLocation(program, "u_density"), + }, + }; }; const createColorShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_texCoord'), - data: new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]) - }], - uniform: { - u_framebuffer: ctx.getUniformLocation(program, 'u_framebuffer'), - u_colorArr: ctx.getUniformLocation(program, 'u_colorArr'), - u_colorCount: ctx.getUniformLocation(program, 'u_colorCount'), - u_opacity: ctx.getUniformLocation(program, 'u_opacity'), - u_offset: ctx.getUniformLocation(program, 'u_offset') - } - }; + const program = createProgram(ctx, shader); + const texCoordBuffer = ctx.createBuffer(); + if (!texCoordBuffer) { + throw new Error("Failed to create texture coordinate buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: texCoordBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_texCoord"), + data: new Float32Array([ + 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, + ]), + }, + ], + uniform: { + u_framebuffer: ctx.getUniformLocation(program, "u_framebuffer"), + u_colorArr: ctx.getUniformLocation(program, "u_colorArr"), + u_colorCount: ctx.getUniformLocation(program, "u_colorCount"), + u_opacity: ctx.getUniformLocation(program, "u_opacity"), + u_offset: ctx.getUniformLocation(program, "u_offset"), + }, + }; }; function isNullUndefined(val) { - return val === null || val === undefined; + return val === null || val === undefined; } function isNotNumber(val) { - return typeof val !== 'number'; + return typeof val !== "number"; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any function isSortedAscending(arr) { - for (let i = 0; i < arr.length - 1; i++) { - if (arr[i + 1].offset - arr[i].offset < 0) { - return false; + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i + 1].offset - arr[i].offset < 0) { + return false; + } } - } - return true; + return true; } - function getPixlRatio(ctx) { - const dpr = window.devicePixelRatio || 1; - const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; - return dpr / bsr; + /** @see https://codereview.chromium.org/156833002/ */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function getPixelRatio(ctx) { + const dpr = window.devicePixelRatio || 1; + const bsr = ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || + 1; + return dpr / bsr; } function gradientMapper(grad) { - if (!Array.isArray(grad) || grad.length < 2) { - throw new Error('Invalid gradient: Expected an array with at least 2 elements.'); - } - if (!isSortedAscending(grad)) { - throw new Error('Invalid gradient: Gradient is not sorted'); - } - const gradLength = grad.length; - const values = new Float32Array(gradLength * 4); - const offsets = new Array(gradLength); - grad.forEach(function (d, i) { - const baseIndex = i * 4; - values[baseIndex] = d.color[0] / 255; - values[baseIndex + 1] = d.color[1] / 255; - values[baseIndex + 2] = d.color[2] / 255; - values[baseIndex + 3] = d.color[3] !== undefined ? d.color[3] : 1.0; - offsets[i] = d.offset; - }); - return { - value: values, - length: gradLength, - offset: offsets - }; + if (!Array.isArray(grad) || grad.length < 2) { + throw new Error("Invalid gradient: Expected an array with at least 2 elements."); + } + if (!isSortedAscending(grad)) { + throw new Error("Invalid gradient: Gradient is not sorted"); + } + const gradLength = grad.length; + const values = new Float32Array(gradLength * 4); + const offsets = new Array(gradLength); + grad.forEach(function (d, i) { + const baseIndex = i * 4; + values[baseIndex] = d.color[0] / 255; + values[baseIndex + 1] = d.color[1] / 255; + values[baseIndex + 2] = d.color[2] / 255; + values[baseIndex + 3] = d.color[3] !== undefined ? d.color[3] : 1.0; + offsets[i] = d.offset; + }); + return { + value: values, + length: gradLength, + offset: offsets, + }; } function extractData(data, self) { - const len = data.length; - let { - posVec = [], - rVec = [] - } = self.hearmapExData || {}; - if (self.pLen !== len) { - self.buffer = new ArrayBuffer(len * 8); - posVec = new Float32Array(self.buffer); - self.buffer2 = new ArrayBuffer(len * 4); - rVec = new Float32Array(self.buffer2); - self.pLen = len; - } - const dataMinMaxValue = { - min: Infinity, - max: -Infinity - }; - for (let i = 0; i < len; i++) { - posVec[i * 2] = data[i].x; - posVec[i * 2 + 1] = data[i].y; - rVec[i] = data[i].value; - if (dataMinMaxValue.min > data[i].value) { - dataMinMaxValue.min = data[i].value; - } - if (dataMinMaxValue.max < data[i].value) { - dataMinMaxValue.max = data[i].value; - } - } - return { - posVec: posVec, - rVec: rVec, - minMax: dataMinMaxValue - }; + const len = data.length; + let { posVec = new Float32Array(), rVec = new Float32Array() } = (self.hearmapExData || {}); + if (self.pLen !== len) { + self.buffer = new ArrayBuffer(len * 8); + posVec = new Float32Array(self.buffer); + self.buffer2 = new ArrayBuffer(len * 4); + rVec = new Float32Array(self.buffer2); + self.pLen = len; + } + const dataMinMaxValue = { + min: Infinity, + max: -Infinity, + }; + for (let i = 0; i < len; i++) { + posVec[i * 2] = data[i].x; + posVec[i * 2 + 1] = data[i].y; + rVec[i] = data[i].value; + if (dataMinMaxValue.min > data[i].value) { + dataMinMaxValue.min = data[i].value; + } + if (dataMinMaxValue.max < data[i].value) { + dataMinMaxValue.max = data[i].value; + } + } + return { + posVec: posVec, + rVec: rVec, + minMax: dataMinMaxValue, + }; } function transCoOr(data) { - const zoomFactor = this.zoom || 0.1; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - const { - angle, - translate - } = this; - - // Combine operations to reduce the number of arithmetic steps - let posX = (data.x - halfWidth) / halfWidth * zoomFactor; - let posY = (data.y - halfHeight) / halfHeight * zoomFactor; - - // Rotate the point if there's an angle - if (angle !== 0.0) { - const cosAngle = Math.cos(angle); - const sinAngle = Math.sin(angle); - posY = sinAngle * posX + cosAngle * posY; - posX = cosAngle * posX - sinAngle * posY; - } - - // Scale back and adjust the position - posX = posX * halfWidth + halfWidth - translate[0]; - posY = posY * halfHeight + halfHeight - translate[1]; - data.x = posX; - data.y = posY; - return { - x: posX, - y: posY - }; + const zoomFactor = this.zoom || 0.1; + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + const { angle, translate } = this; + // Combine operations to reduce the number of arithmetic steps + let posX = ((data.x - halfWidth) / halfWidth) * zoomFactor; + let posY = ((data.y - halfHeight) / halfHeight) * zoomFactor; + // Rotate the point if there's an angle + if (angle !== 0.0) { + const cosAngle = Math.cos(angle); + const sinAngle = Math.sin(angle); + posY = sinAngle * posX + cosAngle * posY; + posX = cosAngle * posX - sinAngle * posY; + } + // Scale back and adjust the position + posX = posX * halfWidth + halfWidth - translate[0]; + posY = posY * halfHeight + halfHeight - translate[1]; + data.x = posX; + data.y = posY; + return { x: posX, y: posY }; } function renderExec() { - const ctx = this.ctx; - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); - ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); - ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, this.width * this.ratio, this.height * this.ratio, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); - ctx.bindFramebuffer(ctx.FRAMEBUFFER, this.fbo); - ctx.framebufferTexture2D(ctx.FRAMEBUFFER, ctx.COLOR_ATTACHMENT0, ctx.TEXTURE_2D, this.fbTexObj, 0); - if (this.hearmapExData) { - renderHeatGrad.call(this, ctx, this.hearmapExData); - } - ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); - if (this.imageConfig) { - renderImage.call(this, ctx, this.imageConfig); - } - renderColorGradiant.call(this, ctx); + const ctx = this.ctx; + if (!ctx) { + return; + } + ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); + ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, this.width * this.ratio, this.height * this.ratio, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); + ctx.bindFramebuffer(ctx.FRAMEBUFFER, this.fbo); + ctx.framebufferTexture2D(ctx.FRAMEBUFFER, ctx.COLOR_ATTACHMENT0, ctx.TEXTURE_2D, this.fbTexObj, 0); + if (this.hearmapExData) { + renderHeatGrad.call(this, ctx, this.hearmapExData); + } + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + if (this.imageConfig) { + renderImage.call(this, ctx, this.imageConfig); + } + renderColorGradiant.call(this, ctx); } function renderHeatGrad(ctx, exData) { - var _exData$minMax$min, _exData$minMax, _exData$minMax$max, _exData$minMax2; - ctx.useProgram(this.gradShadOP.program); - this.min = this.configMin !== null ? this.configMin : (_exData$minMax$min = exData === null || exData === void 0 || (_exData$minMax = exData.minMax) === null || _exData$minMax === void 0 ? void 0 : _exData$minMax.min) !== null && _exData$minMax$min !== void 0 ? _exData$minMax$min : 0; - this.max = this.configMax !== null ? this.configMax : (_exData$minMax$max = exData === null || exData === void 0 || (_exData$minMax2 = exData.minMax) === null || _exData$minMax2 === void 0 ? void 0 : _exData$minMax2.max) !== null && _exData$minMax$max !== void 0 ? _exData$minMax$max : 0; - this.gradShadOP.attr[0].data = exData.posVec || []; - this.gradShadOP.attr[1].data = exData.rVec || []; - ctx.uniform2fv(this.gradShadOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); - ctx.uniform2fv(this.gradShadOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); - ctx.uniform1f(this.gradShadOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); - ctx.uniform1f(this.gradShadOP.uniform.u_angle, this.angle); - ctx.uniform1f(this.gradShadOP.uniform.u_density, this.ratio); - ctx.uniform1f(this.gradShadOP.uniform.u_max, this.max); - ctx.uniform1f(this.gradShadOP.uniform.u_min, this.min); - ctx.uniform1f(this.gradShadOP.uniform.u_size, this.size); - ctx.uniform1f(this.gradShadOP.uniform.u_intensity, this.intensity); - this.gradShadOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - ctx.drawArrays(ctx.POINTS, 0, (exData.posVec || []).length / 2); + var _a, _b, _c, _d; + ctx.useProgram(this.gradShadOP.program); + this.min = + this.configMin !== null ? this.configMin : (_b = (_a = exData === null || exData === void 0 ? void 0 : exData.minMax) === null || _a === void 0 ? void 0 : _a.min) !== null && _b !== void 0 ? _b : 0; + this.max = + this.configMax !== null ? this.configMax : (_d = (_c = exData === null || exData === void 0 ? void 0 : exData.minMax) === null || _c === void 0 ? void 0 : _c.max) !== null && _d !== void 0 ? _d : 0; + this.gradShadOP.attr[0].data = exData.posVec || []; + this.gradShadOP.attr[1].data = exData.rVec || []; + ctx.uniform2fv(this.gradShadOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); + ctx.uniform2fv(this.gradShadOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); + ctx.uniform1f(this.gradShadOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); + ctx.uniform1f(this.gradShadOP.uniform.u_angle, this.angle); + ctx.uniform1f(this.gradShadOP.uniform.u_density, this.ratio); + ctx.uniform1f(this.gradShadOP.uniform.u_max, this.max); + ctx.uniform1f(this.gradShadOP.uniform.u_min, this.min); + ctx.uniform1f(this.gradShadOP.uniform.u_size, this.size); + ctx.uniform1f(this.gradShadOP.uniform.u_intensity, this.intensity); + this.gradShadOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + ctx.drawArrays(ctx.POINTS, 0, (exData.posVec || []).length / 2); } function renderImage(ctx, imageConfig) { - const { - x = 0, - y = 0, - width = 0, - height = 0 - } = imageConfig; - ctx.useProgram(this.imageShaOP.program); - ctx.uniform2fv(this.imageShaOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); - ctx.uniform2fv(this.imageShaOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); - ctx.uniform1f(this.imageShaOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); - ctx.uniform1f(this.imageShaOP.uniform.u_angle, this.angle); - ctx.uniform1f(this.imageShaOP.uniform.u_density, this.ratio); - this.imageShaOP.attr[0].data = new Float32Array([x, y, x + width, y, x, y + height, x, y + height, x + width, y, x + width, y + height]); - this.imageShaOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - ctx.uniform1i(this.imageShaOP.uniform.u_image, 0); - ctx.activeTexture(this.ctx.TEXTURE0); - ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture); - ctx.drawArrays(ctx.TRIANGLES, 0, 6); + const { x = 0, y = 0, width = 0, height = 0 } = imageConfig; + ctx.useProgram(this.imageShaOP.program); + ctx.uniform2fv(this.imageShaOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); + ctx.uniform2fv(this.imageShaOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); + ctx.uniform1f(this.imageShaOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); + ctx.uniform1f(this.imageShaOP.uniform.u_angle, this.angle); + ctx.uniform1f(this.imageShaOP.uniform.u_density, this.ratio); + this.imageShaOP.attr[0].data = new Float32Array([ + x, + y, + x + width, + y, + x, + y + height, + x, + y + height, + x + width, + y, + x + width, + y + height, + ]); + this.imageShaOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + ctx.uniform1i(this.imageShaOP.uniform.u_image, 0); + ctx.activeTexture(this.ctx.TEXTURE0); + ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture); + ctx.drawArrays(ctx.TRIANGLES, 0, 6); } function renderColorGradiant(ctx) { - ctx.useProgram(this.colorShadOP.program); - ctx.uniform4fv(this.colorShadOP.uniform.u_colorArr, this.gradient.value); - ctx.uniform1f(this.colorShadOP.uniform.u_colorCount, this.gradient.length); - ctx.uniform1fv(this.colorShadOP.uniform.u_offset, new Float32Array(this.gradient.offset)); - ctx.uniform1f(this.colorShadOP.uniform.u_opacity, this.opacity); - this.colorShadOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - ctx.uniform1i(this.colorShadOP.uniform.u_framebuffer, 0); - ctx.activeTexture(ctx.TEXTURE0); - ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); - ctx.drawArrays(ctx.TRIANGLES, 0, 6); + ctx.useProgram(this.colorShadOP.program); + ctx.uniform4fv(this.colorShadOP.uniform.u_colorArr, this.gradient.value); + ctx.uniform1f(this.colorShadOP.uniform.u_colorCount, this.gradient.length); + ctx.uniform1fv(this.colorShadOP.uniform.u_offset, new Float32Array(this.gradient.offset)); + ctx.uniform1f(this.colorShadOP.uniform.u_opacity, this.opacity); + this.colorShadOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + ctx.uniform1i(this.colorShadOP.uniform.u_framebuffer, 0); + ctx.activeTexture(ctx.TEXTURE0); + ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); + ctx.drawArrays(ctx.TRIANGLES, 0, 6); } function imageInstance(url, onLoad, onError) { - const imageIns = new Image(); - imageIns.crossOrigin = 'anonymous'; - imageIns.onload = onLoad; - imageIns.onerror = onError; - imageIns.src = url; - return imageIns; + const imageIns = new Image(); + imageIns.crossOrigin = "anonymous"; + imageIns.onload = onLoad; + imageIns.onerror = onError; + imageIns.src = url; + return imageIns; } class HeatmapRenderer { - constructor(container, config) { - try { - const res = typeof container === 'string' ? document.querySelector(container) : container instanceof HTMLElement ? container : null; - if (!res) { - throw new Error('Context must be either a string or an Element'); - } - const { - clientHeight: height, - clientWidth: width - } = res; - const layer = document.createElement('canvas'); - const ctx = layer.getContext('webgl2', { - premultipliedAlpha: false, - depth: false, - antialias: true, - alpha: true, - preserveDrawingBuffer: false - }); - this.ratio = getPixlRatio(ctx); - ctx.clearColor(0, 0, 0, 0); - ctx.enable(ctx.BLEND); - ctx.blendEquation(ctx.FUNC_ADD); - ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); - ctx.depthMask(true); - layer.setAttribute('height', height * this.ratio); - layer.setAttribute('width', width * this.ratio); - layer.style.height = "".concat(height, "px"); - layer.style.width = "".concat(width, "px"); - layer.style.position = 'absolute'; - res.appendChild(layer); - this.ctx = ctx; - this.width = width; - this.height = height; - this.imageConfig = null; - this.configMin = null; - this.configMax = null; - this.hearmapExData = {}; - this.layer = layer; - this.dom = res; - this.gradShadOP = createGradiantShader(this.ctx, GradShader); - this.colorShadOP = createColorShader(this.ctx, ColorShader); - this.imageShaOP = createImageShader(this.ctx, ImageShader); - this.fbTexObj = ctx.createTexture(); - this.fbo = ctx.createFramebuffer(); - if (!isNullUndefined(config.size)) { - this.setSize(config.size); - } else { - this.size = 20.0; - } - if (!isNullUndefined(config.max)) { - this.setMax(config.max); - } else { - this.configMax = null; - } - if (!isNullUndefined(config.min)) { - this.setMin(config.min); - } else { + constructor(container, config) { + this.ctx = null; + this.ratio = 1; + this.width = 0; + this.height = 0; + this.imageConfig = null; this.configMin = null; - } - if (!isNullUndefined(config.intensity)) { - this.setIntensity(config.intensity); - } else { - this.intensity = 1.0; - } - if (!isNullUndefined(config.translate)) { - this.setTranslate(config.translate); - } else { + this.configMax = null; + this.min = 0; + this.max = 0; + this.hearmapExData = {}; + this.size = 0; + this.zoom = 0; + this.angle = 0; + this.intensity = 0; this.translate = [0, 0]; - } - if (!isNullUndefined(config.zoom)) { - this.setZoom(config.zoom); - } else { - this.zoom = 1.0; - } - if (!isNullUndefined(config.angle)) { - this.setRotationAngle(config.angle); - } else { - this.angle = 0.0; - } - if (!isNullUndefined(config.opacity)) { - this.setOpacity(config.opacity); - } else { - this.opacity = 1.0; - } - this.gradient = gradientMapper(config.gradient); - if (config.backgroundImage && config.backgroundImage.url) { - this.setBackgroundImage(config.backgroundImage); - } - this.heatmapData = []; - this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); - } catch (error) { - console.error(error); - } - } - resize() { - const height = this.dom.clientHeight; - const width = this.dom.clientWidth; - this.layer.setAttribute('height', height * this.ratio); - this.layer.setAttribute('width', width * this.ratio); - this.layer.style.height = "".concat(height, "px"); - this.layer.style.width = "".concat(width, "px"); - this.width = width; - this.height = height; - this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); - /* Perform update */ - this.render(this.hearmapExData); - } - clear() { - this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT); - } - setMax(max) { - if (isNullUndefined(max) || isNotNumber(max)) { - throw new Error('Invalid max: Expected Number'); - } - this.configMax = max; - return this; - } - setMin(min) { - if (isNullUndefined(min) || isNotNumber(min)) { - throw new Error('Invalid min: Expected Number'); - } - this.configMin = min; - return this; - } - setGradient(gradient) { - this.gradient = gradientMapper(gradient); - return this; - } - setTranslate(translate) { - if (translate.constructor !== Array) { - throw new Error('Invalid Translate: Translate has to be of Array type'); - } - if (translate.length !== 2) { - throw new Error('Translate has to be of length 2'); - } - this.translate = translate; - return this; - } - setZoom(zoom) { - if (isNullUndefined(zoom) || isNotNumber(zoom)) { - throw new Error('Invalid zoom: Expected Number'); - } - this.zoom = zoom; - return this; - } - setRotationAngle(angle) { - if (isNullUndefined(angle) || isNotNumber(angle)) { - throw new Error('Invalid Angle: Expected Number'); - } - this.angle = angle; - return this; - } - setSize(size) { - if (isNullUndefined(size) || isNotNumber(size)) { - throw new Error('Invalid Size: Expected Number'); - } - this.size = size; - return this; - } - setIntensity(intensity) { - if (isNullUndefined(intensity) || isNotNumber(intensity)) { - this.intensity = 1.0; // applying default intensity - throw new Error('Invalid Intensity: Expected Number'); - } - if (intensity > 1 || intensity < 0) { - this.intensity = intensity > 1 ? 1 : 0; // Setting bound value - throw new Error('Invalid Intensity value ' + intensity); - } - this.intensity = intensity; - return this; - } - setOpacity(opacity) { - if (isNullUndefined(opacity) || isNotNumber(opacity)) { - throw new Error('Invalid Opacity: Expected Number'); - } - if (opacity > 1 || opacity < 0) { - throw new Error('Invalid Opacity value ' + opacity); - } - this.opacity = opacity; - return this; - } - setBackgroundImage(config) { - const self = this; - if (!config.url) { - return; - } - const maxTextureSize = this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE); - this.imageTexture = this.ctx.createTexture(); - this.type = 'TEXTURE_2D'; - this.imageConfig = null; - this.imgWidth = config.width || this.width; - this.imgHeight = config.height || this.height; - this.imgWidth = this.imgWidth > maxTextureSize ? maxTextureSize : this.imgWidth; - this.imgHeight = this.imgHeight > maxTextureSize ? maxTextureSize : this.imgHeight; - imageInstance(config.url, function onUpdateCallBack() { - self.ctx.activeTexture(self.ctx.TEXTURE0); - self.ctx.bindTexture(self.ctx.TEXTURE_2D, self.imageTexture); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_S, self.ctx.CLAMP_TO_EDGE); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_T, self.ctx.CLAMP_TO_EDGE); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MIN_FILTER, self.ctx.LINEAR); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MAG_FILTER, self.ctx.LINEAR); - self.ctx.texImage2D(self.ctx.TEXTURE_2D, 0, self.ctx.RGBA, this.naturalWidth, this.naturalHeight, 0, self.ctx.RGBA, self.ctx.UNSIGNED_BYTE, this); - self.imageConfig = { - x: config.x || 0, - y: config.y || 0, - height: self.imgHeight, - width: self.imgWidth, - image: this - }; - self.render(); - }, function onErrorCallBack(error) { - throw new Error('Image Load Error', error); - }); - return this; - } - clearData() { - this.heatmapData = []; - this.hearmapExData = {}; - this.render(); - } - addData(data, transIntactFlag) { - const self = this; - for (let i = 0; i < data.length; i++) { - if (transIntactFlag) { - transCoOr.call(self, data[i]); - } - this.heatmapData.push(data[i]); - } - this.renderData(this.heatmapData); - return this; - } - renderData(data) { - if (data.constructor !== Array) { - throw new Error('Expected Array type'); - } - this.hearmapExData = extractData(data, this); - this.heatmapData = data; - this.render(); - return this; - } - render() { - renderExec.call(this); - } - projection(data) { - // Pre-compute constants and repetitive calculations - const zoomFactor = this.zoom || 0.1; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - const translateX = this.translate[0]; - const translateY = this.translate[1]; - const angle = this.angle; - const aspect = this.width / this.height; - - // Calculate the adjusted positions - let posX = (data.x + translateX - halfWidth) / (halfWidth * zoomFactor); - let posY = (data.y + translateY - halfHeight) / (halfHeight * zoomFactor); - posX *= aspect; - - // Rotate the point if there's an angle - if (angle !== 0.0) { - const cosAngle = Math.cos(-angle); - const sinAngle = Math.sin(-angle); - const xNew = cosAngle * posX - sinAngle * posY; - posY = sinAngle * posX + cosAngle * posY; - posX = xNew; + this.opacity = 0; + this.gradient = null; + this.imageTexture = null; + this.pLen = undefined; + this.buffer = undefined; + this.buffer2 = undefined; + this.imgWidth = 0; + this.imgHeight = 0; + this.heatmapData = []; + this.type = ""; + try { + const res = typeof container === "string" + ? document.querySelector(container) + : container instanceof HTMLElement + ? container + : null; + if (!res) { + throw new Error("Context must be either a string or an Element"); + } + const { clientHeight: height, clientWidth: width } = res; + const layer = document.createElement("canvas"); + const ctx = layer.getContext("webgl2", { + premultipliedAlpha: false, + depth: false, + antialias: true, + alpha: true, + preserveDrawingBuffer: false, + }); + this.ratio = getPixelRatio(ctx); + ctx.clearColor(0, 0, 0, 0); + ctx.enable(ctx.BLEND); + ctx.blendEquation(ctx.FUNC_ADD); + ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); + ctx.depthMask(true); + layer.setAttribute("height", (height * this.ratio).toString()); + layer.setAttribute("width", (width * this.ratio).toString()); + layer.style.height = `${height}px`; + layer.style.width = `${width}px`; + layer.style.position = "absolute"; + res.appendChild(layer); + this.ctx = ctx; + this.width = width; + this.height = height; + this.imageConfig = null; + this.configMin = null; + this.configMax = null; + this.hearmapExData = {}; + this.layer = layer; + this.dom = res; + this.gradShadOP = createGradiantShader(this.ctx, GradShader); + this.colorShadOP = createColorShader(this.ctx, ColorShader); + this.imageShaOP = createImageShader(this.ctx, ImageShader); + this.fbTexObj = ctx.createTexture(); + this.fbo = ctx.createFramebuffer(); + if (!isNullUndefined(config.size)) { + this.setSize(config.size); + } + else { + this.size = 20.0; + } + if (!isNullUndefined(config.max)) { + this.setMax(config.max); + } + else { + this.configMax = null; + } + if (!isNullUndefined(config.min)) { + this.setMin(config.min); + } + else { + this.configMin = null; + } + if (!isNullUndefined(config.intensity)) { + this.setIntensity(config.intensity); + } + else { + this.intensity = 1.0; + } + if (!isNullUndefined(config.translate)) { + this.setTranslate(config.translate); + } + else { + this.translate = [0, 0]; + } + if (!isNullUndefined(config.zoom)) { + this.setZoom(config.zoom); + } + else { + this.zoom = 1.0; + } + if (!isNullUndefined(config.angle)) { + this.setRotationAngle(config.angle); + } + else { + this.angle = 0.0; + } + if (!isNullUndefined(config.opacity)) { + this.setOpacity(config.opacity); + } + else { + this.opacity = 1.0; + } + this.gradient = gradientMapper(config.gradient); + if (config.backgroundImage && config.backgroundImage.url) { + this.setBackgroundImage(config.backgroundImage); + } + this.heatmapData = []; + this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + } + catch (error) { + console.error(error); + } + } + resize() { + const height = this.dom.clientHeight; + const width = this.dom.clientWidth; + this.layer.setAttribute("height", (height * this.ratio).toString()); + this.layer.setAttribute("width", (width * this.ratio).toString()); + this.layer.style.height = `${height}px`; + this.layer.style.width = `${width}px`; + this.width = width; + this.height = height; + this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + /* Perform update */ + this.render(); + } + clear() { + this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT); + } + setMax(max) { + if (isNullUndefined(max) || isNotNumber(max)) { + throw new Error("Invalid max: Expected Number"); + } + this.configMax = max; + return this; + } + setMin(min) { + if (isNullUndefined(min) || isNotNumber(min)) { + throw new Error("Invalid min: Expected Number"); + } + this.configMin = min; + return this; + } + setGradient(gradient) { + this.gradient = gradientMapper(gradient); + return this; + } + setTranslate(translate) { + if (translate.constructor !== Array) { + throw new Error("Invalid Translate: Translate has to be of Array type"); + } + if (translate.length !== 2) { + throw new Error("Translate has to be of length 2"); + } + this.translate = translate; + return this; + } + setZoom(zoom) { + if (isNullUndefined(zoom) || isNotNumber(zoom)) { + throw new Error("Invalid zoom: Expected Number"); + } + this.zoom = zoom; + return this; + } + setRotationAngle(angle) { + if (isNullUndefined(angle) || isNotNumber(angle)) { + throw new Error("Invalid Angle: Expected Number"); + } + this.angle = angle; + return this; + } + setSize(size) { + if (isNullUndefined(size) || isNotNumber(size)) { + throw new Error("Invalid Size: Expected Number"); + } + this.size = size; + return this; + } + setIntensity(intensity) { + if (isNullUndefined(intensity) || isNotNumber(intensity)) { + this.intensity = 1.0; // applying default intensity + throw new Error("Invalid Intensity: Expected Number"); + } + if (intensity > 1 || intensity < 0) { + this.intensity = intensity > 1 ? 1 : 0; // Setting bound value + throw new Error("Invalid Intensity value " + intensity); + } + this.intensity = intensity; + return this; + } + setOpacity(opacity) { + if (isNullUndefined(opacity) || isNotNumber(opacity)) { + throw new Error("Invalid Opacity: Expected Number"); + } + if (opacity > 1 || opacity < 0) { + throw new Error("Invalid Opacity value " + opacity); + } + this.opacity = opacity; + return this; + } + setBackgroundImage(config) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + if (!config.url) { + return; + } + const maxTextureSize = this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE); + this.imageTexture = this.ctx.createTexture(); + this.type = "TEXTURE_2D"; + this.imageConfig = null; + this.imgWidth = config.width || this.width; + this.imgHeight = config.height || this.height; + this.imgWidth = + this.imgWidth > maxTextureSize ? maxTextureSize : this.imgWidth; + this.imgHeight = + this.imgHeight > maxTextureSize ? maxTextureSize : this.imgHeight; + imageInstance(config.url, function onUpdateCallBack() { + self.ctx.activeTexture(self.ctx.TEXTURE0); + self.ctx.bindTexture(self.ctx.TEXTURE_2D, self.imageTexture); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_S, self.ctx.CLAMP_TO_EDGE); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_T, self.ctx.CLAMP_TO_EDGE); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MIN_FILTER, self.ctx.LINEAR); + self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MAG_FILTER, self.ctx.LINEAR); + self.ctx.texImage2D(self.ctx.TEXTURE_2D, 0, self.ctx.RGBA, this.naturalWidth, this.naturalHeight, 0, self.ctx.RGBA, self.ctx.UNSIGNED_BYTE, this); + self.imageConfig = { + x: config.x || 0, + y: config.y || 0, + height: self.imgHeight, + width: self.imgWidth, + image: this, + }; + self.render(); + }, function onErrorCallBack(error) { + throw new Error(`Image Load Error, ${error}`); + }); + return this; + } + clearData() { + this.heatmapData = []; + this.hearmapExData = {}; + this.render(); } - posX *= 1.0 / aspect; + addData(data, transIntactFlag) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + for (let i = 0; i < data.length; i++) { + if (transIntactFlag) { + transCoOr.call(self, data[i]); + } + this.heatmapData.push(data[i]); + } + this.renderData(this.heatmapData); + return this; + } + renderData(data) { + if (data.constructor !== Array) { + throw new Error("Expected Array type"); + } + this.hearmapExData = extractData(data, this); + this.heatmapData = data; + this.render(); + return this; + } + render() { + renderExec.call(this); + } + projection(data) { + // Pre-compute constants and repetitive calculations + const zoomFactor = this.zoom || 0.1; + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + const translateX = this.translate[0]; + const translateY = this.translate[1]; + const angle = this.angle; + const aspect = this.width / this.height; + // Calculate the adjusted positions + let posX = (data.x + translateX - halfWidth) / (halfWidth * zoomFactor); + let posY = (data.y + translateY - halfHeight) / (halfHeight * zoomFactor); + posX *= aspect; + // Rotate the point if there's an angle + if (angle !== 0.0) { + const cosAngle = Math.cos(-angle); + const sinAngle = Math.sin(-angle); + const xNew = cosAngle * posX - sinAngle * posY; + posY = sinAngle * posX + cosAngle * posY; + posX = xNew; + } + posX *= 1.0 / aspect; + // Scale back and adjust the position + posX = posX * halfWidth + halfWidth; + posY = posY * halfHeight + halfHeight; + return { x: posX, y: posY }; + } + } - // Scale back and adjust the position - posX = posX * halfWidth + halfWidth; - posY = posY * halfHeight + halfHeight; - return { - x: posX, - y: posY - }; - } + // Internal class that encapsulates private properties and methods + class Heatmap { + constructor(context, config) { + this.renderer = new HeatmapRenderer(context, config); + this.ctx = this.renderer.ctx; + this.ratio = this.renderer.ratio; + this.width = this.renderer.width; + this.height = this.renderer.height; + this.min = this.renderer.min; + this.max = this.renderer.max; + this.size = this.renderer.size; + this.zoom = this.renderer.zoom; + this.angle = this.renderer.angle; + this.intensity = this.renderer.intensity; + this.translate = this.renderer.translate; + this.opacity = this.renderer.opacity; + this.gradient = this.renderer.gradient; + this.imageConfig = this.renderer.imageConfig; + } + /** + * Set the maximum data value for relative gradient calculations + * @param max - number + * @returns instance + */ + setMax(max) { + return this.renderer.setMax(max); + } + /** + * Set the minimum data value for relative gradient calculations + * @param min - number + * @returns instance + */ + setMin(min) { + return this.renderer.setMin(min); + } + /** + * Accepts array of objects with color value and offset + * @param gradient - Color Gradient + * @returns instance + */ + setGradient(gradient) { + return this.renderer.setGradient(gradient); + } + /** + * Set the translate transformation on the canvas + * @param translate - Accepts array [x, y] + * @returns instance + */ + setTranslate(translate) { + return this.renderer.setTranslate(translate); + } + /** + * Set the zoom transformation on the canvas + * @param zoom - Accepts float value + * @returns instance + */ + setZoom(zoom) { + return this.renderer.setZoom(zoom); + } + /** + * Set the rotation transformation on the canvas + * @param angle - Accepts angle in radians + * @returns instance + */ + setRotationAngle(angle) { + return this.renderer.setRotationAngle(angle); + } + /** + * Set the point radius + * @param size - Accepts float value + * @returns instance + */ + setSize(size) { + return this.renderer.setSize(size); + } + /** + * Set the intensity factor + * @param intensity - Accepts float value + * @returns instance + */ + setIntensity(intensity) { + return this.renderer.setIntensity(intensity); + } + /** + * Set the opacity factor + * @param opacity - The opacity factor. + * @returns instance + */ + setOpacity(opacity) { + return this.renderer.setOpacity(opacity); + } + /** + * Set the background image + * @param config - Accepts Object with { Url, height, width, x, and y} properties + * @returns instance + */ + setBackgroundImage(config) { + return this.renderer.setBackgroundImage(config); + } + /** + * After adding data points, need to invoke .render() method to update the heatmap + * @param data - The data points with 'x', 'y' and 'value' + * @param transIntactFlag - Flag indicating whether to apply existing heatmap transformations on the newly added data points + * @returns instance + */ + addData(data, transIntactFlag) { + return this.renderer.addData(data, transIntactFlag); + } + /** + * @param data - Accepts an array of data points with 'x', 'y' and 'value' + * @returns instance + */ + renderData(data) { + return this.renderer.renderData(data); + } + /** + * Method to re-render the heatmap. This method needs to be invoked as and when configurations get changed + */ + render() { + this.renderer.render(); + } + /** + * Get projected co-ordinates relative to the heatmap layer + * @param data - The data point to project. + * @returns projected data point. + */ + projection(data) { + return this.renderer.projection(data); + } + /** + * Clears canvas + */ + clear() { + this.renderer.clear(); + } } - function Heatmap(context) { - let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - return new HeatmapRenderer(context, config); + function main (context, config) { + return new Heatmap(context, config); } - return Heatmap; + return main; })); diff --git a/dist/visualHeatmap.min.js b/dist/visualHeatmap.min.js index 474ee66..d043f0b 100644 --- a/dist/visualHeatmap.min.js +++ b/dist/visualHeatmap.min.js @@ -3,4 +3,4 @@ * (c) 2024 Narayana Swamy (narayanaswamy14@gmail.com) * @license BSD-3-Clause */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).visualHeatmap=e()}(this,(function(){"use strict";const t={vertex:"#version 300 es\n\t\t\t\tin vec2 a_position;\n\t\t\t\tin float a_intensity;\n\t\t\t\tuniform float u_size;\n\t\t\t\tuniform vec2 u_resolution;\n\t\t\t\tuniform vec2 u_translate; \n\t\t\t\tuniform float u_zoom; \n\t\t\t\tuniform float u_angle; \n\t\t\t\tuniform float u_density;\n\t\t\t\tout float v_i;\n\n\t\t\t\tvec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 rotationMat = mat2(c, -s, s, c); \n\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\treturn scaleMatInv * rotationMat * scaleMat * v;\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\tfloat zoomFactor = max(u_zoom, 0.1);\n\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle, u_resolution.x / u_resolution.y);\n\t\t\t\t\t}\n\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\tgl_PointSize = u_size * u_density;\n\t\t\t\t\tv_i = a_intensity;\n\t\t\t\t}",fragment:"#version 300 es\n\t\t\t\tprecision mediump float;\n\t\t\t\tuniform float u_max;\n\t\t\t\tuniform float u_min;\n\t\t\t\tuniform float u_intensity;\n\t\t\t\tin float v_i;\n\t\t\t\tout vec4 fragColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat r = 0.0; \n\t\t\t\t\tvec2 cxy = 2.0 * gl_PointCoord - 1.0;\n\t\t\t\t\tr = dot(cxy, cxy);\n\t\t\t\t\tfloat deno = max(u_max - u_min, 1.0);\n\t\t\t\t\tif(r <= 1.0) {\n\t\t\t\t\t\tfragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r)));\n\t\t\t\t\t}\n\t\t\t\t}"},e={vertex:"#version 300 es\n\t\t\t\tprecision highp float;\n\t\t\t\tin vec2 a_texCoord;\n\t\t\t\tout vec2 v_texCoord;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 clipSpace = a_texCoord * 2.0 - 1.0;\n\t\t\t\t\tgl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\t\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t\t}\n\t",fragment:"#version 300 es\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t\tin vec2 v_texCoord;\n\t\t\t\t\tout vec4 fragColor;\n\t\t\t\t\tuniform sampler2D u_framebuffer;\n\t\t\t\t\tuniform vec4 u_colorArr[20];\n\t\t\t\t\tuniform float u_colorCount;\n\t\t\t\t\tuniform float u_opacity;\n\t\t\t\t\tuniform float u_offset[20];\n\n\t\t\t\t\tfloat remap ( float minval, float maxval, float curval ) {\n\t\t\t\t\t\treturn ( curval - minval ) / ( maxval - minval );\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid main() {\n\t\t\t\t\t\tfloat alpha = texture(u_framebuffer, v_texCoord.xy).a;\n\t\t\t\t\t\tif (alpha > 0.0 && alpha <= 1.0) {\n\t\t\t\t\t\t\tvec4 color_;\n\n\t\t\t\t\t\t\tif (alpha <= u_offset[0]) {\n\t\t\t\t\t\t\t\tcolor_ = u_colorArr[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= 20; ++i) {\n\t\t\t\t\t\t\t\t\tif (alpha <= u_offset[i]) {\n\t\t\t\t\t\t\t\t\t\tcolor_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) );\n\t\t\t\t\t\t\t\t\t\tcolor_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha ));\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcolor_ = color_ * u_opacity;\n\t\t\t\t\t\t\tif (color_.a < 0.0) {\n\t\t\t\t\t\t\t\tcolor_.a = 0.0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfragColor = color_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t"},i={vertex:"#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n uniform vec2 u_resolution;\n\t\t\t\t\tuniform vec2 u_translate; \n\t\t\t\t\tuniform float u_zoom; \n\t\t\t\t\tuniform float u_angle; \n\t\t\t\t\tuniform float u_density;\n out vec2 v_texCoord;\n\n vec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c);\n\t\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\treturn scaleMatInv * m * scaleMat * v;\n\t\t\t\t\t}\n\n void main() {\n \tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n \tzeroToOne.y = 1.0 - zeroToOne.y;\n\t\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\t\tfloat zoomFactor = u_zoom;\n\t\t\t\t\t\tif (zoomFactor == 0.0) {\n\t\t\t\t\t\t\tzoomFactor = 0.1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\t\tv_texCoord = a_texCoord;\n }\n \t\t",fragment:"#version 300 es\n precision mediump float;\n uniform sampler2D u_image;\n in vec2 v_texCoord;\n out vec4 fragColor;\n void main() {\n fragColor = texture(u_image, v_texCoord);\n }\n "};function r(t,e,i){var r=t.createShader(t[e]);if(t.shaderSource(r,i),t.compileShader(r),!t.getShaderParameter(r,t.COMPILE_STATUS)){var o=t.getShaderInfoLog(r);throw t.deleteShader(r),new Error("*** Error compiling shader '"+r+"':"+o)}return r}function o(t,e){var i=r(t,"VERTEX_SHADER",e.vertex),o=r(t,"FRAGMENT_SHADER",e.fragment),n=t.createProgram();if(t.attachShader(n,i),t.attachShader(n,o),t.linkProgram(n),t.getProgramParameter(n,t.LINK_STATUS))return n;var a=t.getProgramInfoLog(n);throw t.deleteProgram(n),new Error("Error in program linking:"+a)}function n(t){return null==t}function a(t){return"number"!=typeof t}function s(t){if(!Array.isArray(t)||t.length<2)throw new Error("Invalid gradient: Expected an array with at least 2 elements.");if(!function(t){for(let e=0;e1||t<0)throw this.intensity=t>1?1:0,new Error("Invalid Intensity value "+t);return this.intensity=t,this}setOpacity(t){if(n(t)||a(t))throw new Error("Invalid Opacity: Expected Number");if(t>1||t<0)throw new Error("Invalid Opacity value "+t);return this.opacity=t,this}setBackgroundImage(t){const e=this;if(!t.url)return;const i=this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE);return this.imageTexture=this.ctx.createTexture(),this.type="TEXTURE_2D",this.imageConfig=null,this.imgWidth=t.width||this.width,this.imgHeight=t.height||this.height,this.imgWidth=this.imgWidth>i?i:this.imgWidth,this.imgHeight=this.imgHeight>i?i:this.imgHeight,function(t,e,i){const r=new Image;r.crossOrigin="anonymous",r.onload=e,r.onerror=i,r.src=t}(t.url,(function(){e.ctx.activeTexture(e.ctx.TEXTURE0),e.ctx.bindTexture(e.ctx.TEXTURE_2D,e.imageTexture),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_S,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_T,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MIN_FILTER,e.ctx.LINEAR),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MAG_FILTER,e.ctx.LINEAR),e.ctx.texImage2D(e.ctx.TEXTURE_2D,0,e.ctx.RGBA,this.naturalWidth,this.naturalHeight,0,e.ctx.RGBA,e.ctx.UNSIGNED_BYTE,this),e.imageConfig={x:t.x||0,y:t.y||0,height:e.imgHeight,width:e.imgWidth,image:this},e.render()}),(function(t){throw new Error("Image Load Error",t)})),this}clearData(){this.heatmapData=[],this.hearmapExData={},this.render()}addData(t,e){const i=this;for(let r=0;rt[e].value&&(n.min=t[e].value),n.max1&&void 0!==arguments[1]?arguments[1]:{})}})); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).visualHeatmap=e()}(this,(function(){"use strict";const t={vertex:"#version 300 es\n\t\t\t\tin vec2 a_position;\n\t\t\t\tin float a_intensity;\n\t\t\t\tuniform float u_size;\n\t\t\t\tuniform vec2 u_resolution;\n\t\t\t\tuniform vec2 u_translate; \n\t\t\t\tuniform float u_zoom; \n\t\t\t\tuniform float u_angle; \n\t\t\t\tuniform float u_density;\n\t\t\t\tout float v_i;\n\n\t\t\t\tvec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 rotationMat = mat2(c, -s, s, c); \n\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\treturn scaleMatInv * rotationMat * scaleMat * v;\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\tfloat zoomFactor = max(u_zoom, 0.1);\n\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle, u_resolution.x / u_resolution.y);\n\t\t\t\t\t}\n\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\tgl_PointSize = u_size * u_density;\n\t\t\t\t\tv_i = a_intensity;\n\t\t\t\t}",fragment:"#version 300 es\n\t\t\t\tprecision mediump float;\n\t\t\t\tuniform float u_max;\n\t\t\t\tuniform float u_min;\n\t\t\t\tuniform float u_intensity;\n\t\t\t\tin float v_i;\n\t\t\t\tout vec4 fragColor;\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat r = 0.0; \n\t\t\t\t\tvec2 cxy = 2.0 * gl_PointCoord - 1.0;\n\t\t\t\t\tr = dot(cxy, cxy);\n\t\t\t\t\tfloat deno = max(u_max - u_min, 1.0);\n\t\t\t\t\tif(r <= 1.0) {\n\t\t\t\t\t\tfragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r)));\n\t\t\t\t\t}\n\t\t\t\t}"},e={vertex:"#version 300 es\n\t\t\t\tprecision highp float;\n\t\t\t\tin vec2 a_texCoord;\n\t\t\t\tout vec2 v_texCoord;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 clipSpace = a_texCoord * 2.0 - 1.0;\n\t\t\t\t\tgl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\t\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t\t}\n\t",fragment:"#version 300 es\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t\tin vec2 v_texCoord;\n\t\t\t\t\tout vec4 fragColor;\n\t\t\t\t\tuniform sampler2D u_framebuffer;\n\t\t\t\t\tuniform vec4 u_colorArr[20];\n\t\t\t\t\tuniform float u_colorCount;\n\t\t\t\t\tuniform float u_opacity;\n\t\t\t\t\tuniform float u_offset[20];\n\n\t\t\t\t\tfloat remap ( float minval, float maxval, float curval ) {\n\t\t\t\t\t\treturn ( curval - minval ) / ( maxval - minval );\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid main() {\n\t\t\t\t\t\tfloat alpha = texture(u_framebuffer, v_texCoord.xy).a;\n\t\t\t\t\t\tif (alpha > 0.0 && alpha <= 1.0) {\n\t\t\t\t\t\t\tvec4 color_;\n\n\t\t\t\t\t\t\tif (alpha <= u_offset[0]) {\n\t\t\t\t\t\t\t\tcolor_ = u_colorArr[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= 20; ++i) {\n\t\t\t\t\t\t\t\t\tif (alpha <= u_offset[i]) {\n\t\t\t\t\t\t\t\t\t\tcolor_ = mix( u_colorArr[i - 1], u_colorArr[i], remap( u_offset[i - 1], u_offset[i], alpha ) );\n\t\t\t\t\t\t\t\t\t\tcolor_ = color_ * mix( u_colorArr[i - 1][3], u_colorArr[i][3], remap( u_offset[i - 1], u_offset[i], alpha ));\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcolor_ = color_ * u_opacity;\n\t\t\t\t\t\t\tif (color_.a < 0.0) {\n\t\t\t\t\t\t\t\tcolor_.a = 0.0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfragColor = color_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t"},r={vertex:"#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n uniform vec2 u_resolution;\n\t\t\t\t\tuniform vec2 u_translate; \n\t\t\t\t\tuniform float u_zoom; \n\t\t\t\t\tuniform float u_angle; \n\t\t\t\t\tuniform float u_density;\n out vec2 v_texCoord;\n\n vec2 rotation(vec2 v, float a, float aspect) {\n\t\t\t\t\t\tfloat s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c);\n\t\t\t\t\t\tmat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\tmat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);\n\t\t\t\t\t\treturn scaleMatInv * m * scaleMat * v;\n\t\t\t\t\t}\n\n void main() {\n \tvec2 zeroToOne = (a_position * u_density + u_translate * u_density) / (u_resolution);\n \tzeroToOne.y = 1.0 - zeroToOne.y;\n\t\t\t\t\t\tvec2 zeroToTwo = zeroToOne * 2.0 - 1.0;\n\t\t\t\t\t\tfloat zoomFactor = u_zoom;\n\t\t\t\t\t\tif (zoomFactor == 0.0) {\n\t\t\t\t\t\t\tzoomFactor = 0.1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tzeroToTwo = zeroToTwo / zoomFactor;\n\t\t\t\t\t\tif (u_angle != 0.0) {\n\t\t\t\t\t\t\tzeroToTwo = rotation(zeroToTwo, u_angle * -1.0, u_resolution.x / u_resolution.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl_Position = vec4(zeroToTwo , 0, 1);\n\t\t\t\t\t\tv_texCoord = a_texCoord;\n }\n \t\t",fragment:"#version 300 es\n precision mediump float;\n uniform sampler2D u_image;\n in vec2 v_texCoord;\n out vec4 fragColor;\n void main() {\n fragColor = texture(u_image, v_texCoord);\n }\n "};function i(t,e,r){const i=t.createShader(t[e]);if(!i)throw new Error("Failed to create shader.");t.shaderSource(i,r),t.compileShader(i);if(!t.getShaderParameter(i,t.COMPILE_STATUS)){const e=t.getShaderInfoLog(i);throw t.deleteShader(i),new Error("*** Error compiling shader '"+i+"':"+e)}return i}function n(t,e){const r=i(t,"VERTEX_SHADER",e.vertex),n=i(t,"FRAGMENT_SHADER",e.fragment),o=t.createProgram();if(!o)throw new Error("Failed to create program.");t.attachShader(o,r),t.attachShader(o,n),t.linkProgram(o);if(t.getProgramParameter(o,t.LINK_STATUS))return o;{const e=t.getProgramInfoLog(o);throw t.deleteProgram(o),new Error("Error in program linking:"+e)}}function o(t){return null==t}function a(t){return"number"!=typeof t}function s(t){if(!Array.isArray(t)||t.length<2)throw new Error("Invalid gradient: Expected an array with at least 2 elements.");if(!function(t){for(let e=0;e1||t<0)throw this.intensity=t>1?1:0,new Error("Invalid Intensity value "+t);return this.intensity=t,this}setOpacity(t){if(o(t)||a(t))throw new Error("Invalid Opacity: Expected Number");if(t>1||t<0)throw new Error("Invalid Opacity value "+t);return this.opacity=t,this}setBackgroundImage(t){const e=this;if(!t.url)return;const r=this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE);return this.imageTexture=this.ctx.createTexture(),this.type="TEXTURE_2D",this.imageConfig=null,this.imgWidth=t.width||this.width,this.imgHeight=t.height||this.height,this.imgWidth=this.imgWidth>r?r:this.imgWidth,this.imgHeight=this.imgHeight>r?r:this.imgHeight,function(t,e,r){const i=new Image;i.crossOrigin="anonymous",i.onload=e,i.onerror=r,i.src=t}(t.url,(function(){e.ctx.activeTexture(e.ctx.TEXTURE0),e.ctx.bindTexture(e.ctx.TEXTURE_2D,e.imageTexture),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_S,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_WRAP_T,e.ctx.CLAMP_TO_EDGE),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MIN_FILTER,e.ctx.LINEAR),e.ctx.texParameteri(e.ctx.TEXTURE_2D,e.ctx.TEXTURE_MAG_FILTER,e.ctx.LINEAR),e.ctx.texImage2D(e.ctx.TEXTURE_2D,0,e.ctx.RGBA,this.naturalWidth,this.naturalHeight,0,e.ctx.RGBA,e.ctx.UNSIGNED_BYTE,this),e.imageConfig={x:t.x||0,y:t.y||0,height:e.imgHeight,width:e.imgWidth,image:this},e.render()}),(function(t){throw new Error(`Image Load Error, ${t}`)})),this}clearData(){this.heatmapData=[],this.hearmapExData={},this.render()}addData(t,e){const r=this;for(let i=0;it[e].value&&(o.min=t[e].value),o.max=8.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint-community/regexpp": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", @@ -1829,23 +1821,26 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { @@ -1858,14 +1853,14 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -1885,9 +1880,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@jridgewell/gen-mapping": { @@ -2009,28 +2004,48 @@ } } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "22.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", - "integrity": "sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==", + "node_modules/@rollup/plugin-eslint": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-eslint/-/plugin-eslint-9.0.5.tgz", + "integrity": "sha512-C4nh0sSeJuxVW5u5tDX+dCMjKcNfHm4hS+zeUVh1si7gttnhgGbrmPkUxIX7iZgYABwdEh/ewyMbZB+WXjSJdA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "eslint": "^8.24.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", "dev": true, "dependencies": { "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 10.0.0" }, "peerDependencies": { - "rollup": "^2.68.0" + "rollup": "^2.42.0" } }, - "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils": { + "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", @@ -2047,424 +2062,420 @@ "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@rollup/plugin-commonjs/node_modules/@types/estree": { + "node_modules/@rollup/plugin-node-resolve/node_modules/@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true }, - "node_modules/@rollup/plugin-eslint": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@rollup/plugin-eslint/-/plugin-eslint-9.0.5.tgz", - "integrity": "sha512-C4nh0sSeJuxVW5u5tDX+dCMjKcNfHm4hS+zeUVh1si7gttnhgGbrmPkUxIX7iZgYABwdEh/ewyMbZB+WXjSJdA==", + "node_modules/@rollup/plugin-node-resolve/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "eslint": "^8.24.0" + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" }, "peerDependenciesMeta": { "rollup": { "optional": true + }, + "tslib": { + "optional": true } } }, - "node_modules/@rollup/plugin-eslint/node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=14.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@rollup/plugin-eslint/node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, - "engines": { - "node": ">=10.10.0" + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@rollup/plugin-eslint/node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "node_modules/@rollup/plugin-eslint/node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "peer": true + }, + "node_modules/@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" } }, - "node_modules/@rollup/plugin-eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "@types/node": "*" } }, - "node_modules/@rollup/plugin-eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, - "node_modules/@rollup/plugin-eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", + "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/type-utils": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@rollup/plugin-eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "yallist": "^4.0.0" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@rollup/plugin-eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@rollup/plugin-eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@rollup/plugin-eslint/node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "lru-cache": "^6.0.0" }, "bin": { - "eslint": "bin/eslint.js" + "semver": "bin/semver.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=10" } }, - "node_modules/@rollup/plugin-eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", + "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@rollup/plugin-eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", + "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@rollup/plugin-eslint/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", + "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", "dev": true, "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@rollup/plugin-eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/@typescript-eslint/types": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", + "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", "dev": true, "engines": { - "node": ">=4.0" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@rollup/plugin-eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", + "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", "dev": true, "dependencies": { - "is-glob": "^4.0.3" + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@rollup/plugin-eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@rollup/plugin-eslint/node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true, - "engines": { - "node": ">= 4" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@rollup/plugin-eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "balanced-match": "^1.0.0" } }, - "node_modules/@rollup/plugin-eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 10.0.0" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "rollup": "^2.42.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "lru-cache": "^6.0.0" }, - "engines": { - "node": ">= 8.0.0" + "bin": { + "semver": "bin/semver.js" }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "engines": { + "node": ">=10" } }, - "node_modules/@rollup/plugin-node-resolve/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@rollup/plugin-node-resolve/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "node_modules/@typescript-eslint/utils": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", + "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", "dev": true, "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "semver": "^7.6.0" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "node": "^18.18.0 || >=20.0.0" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "peer": true + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/@types/node": { - "version": "20.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", - "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", + "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", "dev": true, "dependencies": { - "@types/node": "*" + "@typescript-eslint/types": "7.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@ungap/structured-clone": { @@ -2474,11 +2485,10 @@ "dev": true }, "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2511,15 +2521,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2542,13 +2543,10 @@ } }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", @@ -2584,6 +2582,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/array.prototype.findlastindex": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", @@ -2664,15 +2671,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -2741,6 +2739,18 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.23.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", @@ -2870,12 +2880,6 @@ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2980,6 +2984,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2998,25 +3014,6 @@ "integrity": "sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==", "dev": true }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/es-abstract": { "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", @@ -3133,57 +3130,55 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3363,16 +3358,6 @@ "eslint": ">=5.16.0" } }, - "node_modules/eslint-plugin-node/node_modules/ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha1-hLez2+ZFUrbvDsqZ9nQ9vsbZet8=", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/eslint-plugin-promise": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", @@ -3408,16 +3393,19 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-utils": { @@ -3425,6 +3413,7 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "peer": true, "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -3440,17 +3429,21 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, + "peer": true, "engines": { "node": ">=4" } }, "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -3523,33 +3516,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3562,58 +3528,21 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -3628,15 +3557,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3649,7 +3569,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -3658,15 +3578,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -3679,15 +3590,43 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, "node_modules/fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -3721,6 +3660,18 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3830,12 +3781,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -3918,15 +3863,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/globals": { @@ -3960,6 +3905,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -4066,9 +4031,9 @@ } }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -4240,15 +4205,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4280,6 +4236,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-number-object": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", @@ -4305,15 +4270,6 @@ "node": ">=8" } }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4453,13 +4409,12 @@ "dev": true }, "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -4554,12 +4509,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4569,21 +4518,34 @@ "yallist": "^3.0.2" } }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4813,6 +4775,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4840,15 +4811,6 @@ "node": ">= 0.8.0" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -4931,6 +4893,7 @@ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, + "peer": true, "engines": { "node": ">=8" }, @@ -5019,15 +4982,6 @@ "node": ">=4" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -5264,56 +5218,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5333,33 +5246,6 @@ "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -5466,44 +5352,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/terser": { "version": "5.26.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", @@ -5522,18 +5370,6 @@ "node": ">=10" } }, - "node_modules/terser/node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5549,6 +5385,30 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -5562,6 +5422,12 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5655,6 +5521,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typescript": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -5716,12 +5595,6 @@ "punycode": "^2.1.0" } }, - "node_modules/v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", - "dev": true - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7035,14 +6908,6 @@ "dev": true, "requires": { "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - } } }, "@eslint-community/regexpp": { @@ -7052,19 +6917,19 @@ "dev": true }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, @@ -7075,14 +6940,14 @@ "dev": true }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" } }, "@humanwhocodes/module-importer": { @@ -7092,9 +6957,9 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "@jridgewell/gen-mapping": { @@ -7172,56 +7037,14 @@ "fastq": "^1.6.0" } }, - "@rollup/plugin-babel": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", - "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@rollup/pluginutils": "^5.0.1" - } - }, - "@rollup/plugin-commonjs": { - "version": "22.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", - "integrity": "sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "dependencies": { - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - } - } - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - } + "@rollup/plugin-babel": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", + "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" } }, "@rollup/plugin-eslint": { @@ -7232,212 +7055,6 @@ "requires": { "@rollup/pluginutils": "^5.0.1", "eslint": "^8.24.0" - }, - "dependencies": { - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true - }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - } - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "@rollup/plugin-node-resolve": { @@ -7479,6 +7096,16 @@ } } }, + "@rollup/plugin-typescript": { + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + } + }, "@rollup/pluginutils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", @@ -7496,6 +7123,12 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -7521,6 +7154,209 @@ "@types/node": "*" } }, + "@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", + "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/type-utils": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", + "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", + "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", + "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + } + }, + "@typescript-eslint/types": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", + "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", + "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", + "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "semver": "^7.6.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", + "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.7.0", + "eslint-visitor-keys": "^3.4.3" + } + }, "@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -7528,11 +7364,10 @@ "dev": true }, "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "peer": true + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true }, "acorn-jsx": { "version": "5.3.2", @@ -7553,12 +7388,6 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -7575,13 +7404,10 @@ } }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-buffer-byte-length": { "version": "1.0.0", @@ -7608,6 +7434,12 @@ "is-string": "^1.0.7" } }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "array.prototype.findlastindex": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", @@ -7664,12 +7496,6 @@ "is-shared-array-buffer": "^1.0.2" } }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -7723,6 +7549,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browserslist": { "version": "4.23.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", @@ -7800,13 +7635,7 @@ "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "concat-map": { @@ -7886,6 +7715,15 @@ "object-keys": "^1.1.1" } }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -7901,22 +7739,6 @@ "integrity": "sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==", "dev": true }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - } - }, "es-abstract": { "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", @@ -8012,51 +7834,49 @@ "dev": true }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "dependencies": { "ansi-styles": { @@ -8105,24 +7925,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8131,12 +7933,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } } }, @@ -8274,15 +8070,6 @@ "minimatch": "^3.0.4", "resolve": "^1.10.1", "semver": "^6.1.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha1-hLez2+ZFUrbvDsqZ9nQ9vsbZet8=", - "dev": true, - "peer": true - } } }, "eslint-plugin-promise": { @@ -8301,13 +8088,13 @@ "requires": {} }, "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" } }, "eslint-utils": { @@ -8315,6 +8102,7 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "peer": true, "requires": { "eslint-visitor-keys": "^1.1.0" }, @@ -8323,47 +8111,28 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true + "dev": true, + "peer": true } } }, "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", @@ -8371,14 +8140,6 @@ "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "esrecurse": { @@ -8388,20 +8149,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "estree-walker": { @@ -8422,6 +8175,30 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -8452,6 +8229,15 @@ "flat-cache": "^3.0.4" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8532,12 +8318,6 @@ "functions-have-names": "^1.2.3" } }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -8596,12 +8376,12 @@ } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "globals": { @@ -8623,6 +8403,20 @@ "define-properties": "^1.1.3" } }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -8696,9 +8490,9 @@ } }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true }, "import-fresh": { @@ -8819,12 +8613,6 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -8847,6 +8635,12 @@ "dev": true, "peer": true }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-number-object": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", @@ -8863,15 +8657,6 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -8974,13 +8759,12 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsesc": { @@ -9057,12 +8841,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -9072,21 +8850,28 @@ "yallist": "^3.0.2" } }, - "magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.8" - } - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -9259,6 +9044,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -9277,12 +9068,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -9341,7 +9126,8 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true + "dev": true, + "peer": true }, "regexpu-core": { "version": "5.3.2", @@ -9405,12 +9191,6 @@ } } }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, "resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -9571,42 +9351,11 @@ "object-inspect": "^1.9.0" } }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true }, "source-map": { "version": "0.6.1", @@ -9624,29 +9373,6 @@ "source-map": "^0.6.0" } }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, "string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -9720,39 +9446,6 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, - "table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, "terser": { "version": "5.26.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", @@ -9763,14 +9456,6 @@ "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" - }, - "dependencies": { - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true - } } }, "text-table": { @@ -9785,6 +9470,22 @@ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "requires": {} + }, "tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -9798,6 +9499,12 @@ "strip-bom": "^3.0.0" } }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9864,6 +9571,12 @@ "is-typed-array": "^1.1.9" } }, + "typescript": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "dev": true + }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -9902,12 +9615,6 @@ "punycode": "^2.1.0" } }, - "v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", - "dev": true - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 2eac28d..d822e4c 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "\"Advanced Visual Heatmap - High Scale webGL based rendering.\"", "module": "./dist/visualHeatmap.esm.js", "main": "./dist/visualHeatmap.js", + "types": "./dist/main.d.ts", "scripts": { "dev": "rollup -wm -c rollup.config.js", "build": "rm -rf ./dist/ && rollup -c rollup.config.js" @@ -34,13 +35,17 @@ "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-commonjs": "^22.0.2", "@rollup/plugin-eslint": "^9.0.5", "@rollup/plugin-node-resolve": "^13.3.0", - "eslint": "^7.32.0", + "@rollup/plugin-typescript": "^11.1.6", + "@typescript-eslint/eslint-plugin": "^7.7.0", + "@typescript-eslint/parser": "^7.7.0", + "eslint": "^8.56.0", "eslint-config-prettier": "^6.15.0", "eslint-config-standard": "^14.1.1", "rollup": "^2.79.1", - "rollup-plugin-terser": "^7.0.0" + "rollup-plugin-terser": "^7.0.0", + "tslib": "^2.6.2", + "typescript": "^5.4.4" } } diff --git a/rollup.config.js b/rollup.config.js index bef00f2..0828fa1 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,7 +1,7 @@ -import commonjs from "@rollup/plugin-commonjs"; import eslint from '@rollup/plugin-eslint'; -import { terser } from "rollup-plugin-terser"; +import { terser } from 'rollup-plugin-terser'; import babel from '@rollup/plugin-babel'; +import typescript from '@rollup/plugin-typescript'; const version = process.env.VERSION || require('./package.json').version; const author = require('./package.json').author; @@ -15,7 +15,7 @@ const banner = */`; export default [{ - input: './src/main.js', + input: './src/main.ts', output: [{ banner, file: 'dist/visualHeatmap.esm.js', @@ -28,21 +28,18 @@ export default [{ name: 'visualHeatmap' }], plugins: [ - // babel({ - // babelHelpers: 'bundled', - // exclude: 'node_modules/**', // Don't transpile node_modules - // }), - // commonjs(), + typescript(), eslint({ fix: true, throwOnError: true }), babel({ babelHelpers: 'bundled', - exclude: 'node_modules/**', // Don't transpile node_modules - })] + exclude: 'node_modules/**' // Don't transpile node_modules + }), + ] }, { - input: './src/main.js', + input: './src/main.ts', output: [{ file: 'dist/visualHeatmap.min.js', banner, @@ -57,8 +54,7 @@ export default [{ compact: true }], plugins: [ - - // commonjs(), + typescript(), terser(), eslint({ fix: true, @@ -66,6 +62,6 @@ export default [{ }), babel({ babelHelpers: 'bundled', - exclude: 'node_modules/**', // Don't transpile node_modules + exclude: 'node_modules/**' // Don't transpile node_modules })] }]; diff --git a/src/heatmap.js b/src/heatmap.js deleted file mode 100644 index bd31fa7..0000000 --- a/src/heatmap.js +++ /dev/null @@ -1,535 +0,0 @@ -import { GradShader, ColorShader, ImageShader } from './shaders.js'; -import { createImageShader, createGradiantShader, createColorShader } from './utils/shaderUtils.js'; -import { isNullUndefined, isNotNumber, isSortedAscending, getPixlRatio } from './utils/utils.js'; - -function gradientMapper (grad) { - if (!Array.isArray(grad) || grad.length < 2) { - throw new Error('Invalid gradient: Expected an array with at least 2 elements.'); - } - - if (!isSortedAscending(grad)) { - throw new Error('Invalid gradient: Gradient is not sorted'); - } - - const gradLength = grad.length; - const values = new Float32Array(gradLength * 4); - const offsets = new Array(gradLength); - - grad.forEach(function (d, i) { - const baseIndex = i * 4; - values[baseIndex] = d.color[0] / 255; - values[baseIndex + 1] = d.color[1] / 255; - values[baseIndex + 2] = d.color[2] / 255; - values[baseIndex + 3] = d.color[3] !== undefined ? d.color[3] : 1.0; - offsets[i] = d.offset; - }); - - return { - value: values, - length: gradLength, - offset: offsets - }; -} - -function extractData (data, self) { - const len = data.length; - let { posVec = [], rVec = [] } = self.hearmapExData || {}; - if (self.pLen !== len) { - self.buffer = new ArrayBuffer(len * 8); - posVec = new Float32Array(self.buffer); - self.buffer2 = new ArrayBuffer(len * 4); - rVec = new Float32Array(self.buffer2); - self.pLen = len; - } - const dataMinMaxValue = { - min: Infinity, - max: -Infinity - }; - for (let i = 0; i < len; i++) { - posVec[i * 2] = data[i].x; - posVec[(i * 2) + 1] = data[i].y; - rVec[i] = data[i].value; - if (dataMinMaxValue.min > data[i].value) { - dataMinMaxValue.min = data[i].value; - } - if (dataMinMaxValue.max < data[i].value) { - dataMinMaxValue.max = data[i].value; - } - } - - return { - posVec: posVec, - rVec: rVec, - minMax: dataMinMaxValue - }; -} - -function transCoOr (data) { - const zoomFactor = this.zoom || 0.1; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - const { angle, translate } = this; - - // Combine operations to reduce the number of arithmetic steps - let posX = (data.x - halfWidth) / halfWidth * zoomFactor; - let posY = (data.y - halfHeight) / halfHeight * zoomFactor; - - // Rotate the point if there's an angle - if (angle !== 0.0) { - const cosAngle = Math.cos(angle); - const sinAngle = Math.sin(angle); - posY = (sinAngle * posX) + (cosAngle * posY); - posX = (cosAngle * posX) - (sinAngle * posY); - } - - // Scale back and adjust the position - posX = (posX * halfWidth) + halfWidth - translate[0]; - posY = (posY * halfHeight) + halfHeight - translate[1]; - - data.x = posX; - data.y = posY; - - return { x: posX, y: posY }; -} - - -function renderExec () { - const ctx = this.ctx; - - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); - - ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); - ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, this.width * this.ratio, this.height * this.ratio, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); - - ctx.bindFramebuffer(ctx.FRAMEBUFFER, this.fbo); - ctx.framebufferTexture2D(ctx.FRAMEBUFFER, ctx.COLOR_ATTACHMENT0, ctx.TEXTURE_2D, this.fbTexObj, 0); - - if (this.hearmapExData) { - renderHeatGrad.call(this, ctx, this.hearmapExData); - } - ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); - if (this.imageConfig) { - renderImage.call(this, ctx, this.imageConfig); - } - renderColorGradiant.call(this, ctx); -}; - -function renderHeatGrad (ctx, exData) { - ctx.useProgram(this.gradShadOP.program); - - this.min = this.configMin !== null ? this.configMin : exData?.minMax?.min ?? 0; - this.max = this.configMax !== null ? this.configMax : exData?.minMax?.max ?? 0; - this.gradShadOP.attr[0].data = exData.posVec || []; - this.gradShadOP.attr[1].data = exData.rVec || []; - - ctx.uniform2fv(this.gradShadOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); - ctx.uniform2fv(this.gradShadOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); - ctx.uniform1f(this.gradShadOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); - ctx.uniform1f(this.gradShadOP.uniform.u_angle, this.angle); - ctx.uniform1f(this.gradShadOP.uniform.u_density, this.ratio); - ctx.uniform1f(this.gradShadOP.uniform.u_max, this.max); - ctx.uniform1f(this.gradShadOP.uniform.u_min, this.min); - ctx.uniform1f(this.gradShadOP.uniform.u_size, this.size); - ctx.uniform1f(this.gradShadOP.uniform.u_intensity, this.intensity); - - this.gradShadOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - - ctx.drawArrays(ctx.POINTS, 0, (exData.posVec || []).length / 2); -} - -function renderImage (ctx, imageConfig) { - const { x = 0, y = 0, width = 0, height = 0 } = imageConfig; - - ctx.useProgram(this.imageShaOP.program); - - ctx.uniform2fv(this.imageShaOP.uniform.u_resolution, new Float32Array([this.width * this.ratio, this.height * this.ratio])); - ctx.uniform2fv(this.imageShaOP.uniform.u_translate, new Float32Array([this.translate[0], this.translate[1]])); - ctx.uniform1f(this.imageShaOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); - ctx.uniform1f(this.imageShaOP.uniform.u_angle, this.angle); - ctx.uniform1f(this.imageShaOP.uniform.u_density, this.ratio); - - this.imageShaOP.attr[0].data = new Float32Array([x, y, x + width, y, x, y + height, x, y + height, x + width, y, x + width, y + height]); - - this.imageShaOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - - ctx.uniform1i(this.imageShaOP.uniform.u_image, 0); - ctx.activeTexture(this.ctx.TEXTURE0); - ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture); - ctx.drawArrays(ctx.TRIANGLES, 0, 6); -} - -function renderColorGradiant (ctx) { - ctx.useProgram(this.colorShadOP.program); - - ctx.uniform4fv(this.colorShadOP.uniform.u_colorArr, this.gradient.value); - ctx.uniform1f(this.colorShadOP.uniform.u_colorCount, this.gradient.length); - ctx.uniform1fv(this.colorShadOP.uniform.u_offset, new Float32Array(this.gradient.offset)); - ctx.uniform1f(this.colorShadOP.uniform.u_opacity, this.opacity); - - this.colorShadOP.attr.forEach(function (d) { - ctx.bindBuffer(d.bufferType, d.buffer); - ctx.bufferData(d.bufferType, d.data, d.drawType); - ctx.enableVertexAttribArray(d.attribute); - ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); - }); - - ctx.uniform1i(this.colorShadOP.uniform.u_framebuffer, 0); - ctx.activeTexture(ctx.TEXTURE0); - ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); - - ctx.drawArrays(ctx.TRIANGLES, 0, 6); -} - - -function imageInstance (url, onLoad, onError) { - const imageIns = new Image(); - imageIns.crossOrigin = 'anonymous'; - imageIns.onload = onLoad; - imageIns.onerror = onError; - imageIns.src = url; - - return imageIns; -} - -export class HeatmapRenderer { - constructor (container, config) { - try { - const res = typeof container === 'string' ? document.querySelector(container) : container instanceof HTMLElement ? container : null; - if (!res) { - throw new Error('Context must be either a string or an Element'); - } - const { clientHeight: height, clientWidth: width } = res; - const layer = document.createElement('canvas'); - const ctx = layer.getContext('webgl2', { - premultipliedAlpha: false, - depth: false, - antialias: true, - alpha: true, - preserveDrawingBuffer: false - }); - this.ratio = getPixlRatio(ctx); - ctx.clearColor(0, 0, 0, 0); - ctx.enable(ctx.BLEND); - ctx.blendEquation(ctx.FUNC_ADD); - ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); - ctx.depthMask(true); - layer.setAttribute('height', height * this.ratio); - layer.setAttribute('width', width * this.ratio); - layer.style.height = `${height}px`; - layer.style.width = `${width}px`; - layer.style.position = 'absolute'; - res.appendChild(layer); - - this.ctx = ctx; - this.width = width; - this.height = height; - this.imageConfig = null; - this.configMin = null; - this.configMax = null; - this.hearmapExData = {}; - this.layer = layer; - this.dom = res; - this.gradShadOP = createGradiantShader(this.ctx, GradShader); - this.colorShadOP = createColorShader(this.ctx, ColorShader); - this.imageShaOP = createImageShader(this.ctx, ImageShader); - this.fbTexObj = ctx.createTexture(); - this.fbo = ctx.createFramebuffer(); - - if (!isNullUndefined(config.size)) { - this.setSize(config.size); - } else { - this.size = 20.0; - } - - if (!isNullUndefined(config.max)) { - this.setMax(config.max); - } else { - this.configMax = null; - } - - if (!isNullUndefined(config.min)) { - this.setMin(config.min); - } else { - this.configMin = null; - } - - if (!isNullUndefined(config.intensity)) { - this.setIntensity(config.intensity); - } else { - this.intensity = 1.0; - } - - if (!isNullUndefined(config.translate)) { - this.setTranslate(config.translate); - } else { - this.translate = [0, 0]; - } - - if (!isNullUndefined(config.zoom)) { - this.setZoom(config.zoom); - } else { - this.zoom = 1.0; - } - - if (!isNullUndefined(config.angle)) { - this.setRotationAngle(config.angle); - } else { - this.angle = 0.0; - } - - if (!isNullUndefined(config.opacity)) { - this.setOpacity(config.opacity); - } else { - this.opacity = 1.0; - } - - this.gradient = gradientMapper(config.gradient); - - if (config.backgroundImage && config.backgroundImage.url) { - this.setBackgroundImage(config.backgroundImage); - } - - this.heatmapData = []; - - this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); - } catch (error) { - console.error(error); - } - } - - resize () { - const height = this.dom.clientHeight; - const width = this.dom.clientWidth; - this.layer.setAttribute('height', height * this.ratio); - this.layer.setAttribute('width', width * this.ratio); - this.layer.style.height = `${height}px`; - this.layer.style.width = `${width}px`; - this.width = width; - this.height = height; - this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); - /* Perform update */ - this.render(this.hearmapExData); - } - - clear () { - this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT); - } - - setMax (max) { - if (isNullUndefined(max) || isNotNumber(max)) { - throw new Error('Invalid max: Expected Number'); - } - - this.configMax = max; - return this; - } - - setMin (min) { - if (isNullUndefined(min) || isNotNumber(min)) { - throw new Error('Invalid min: Expected Number'); - } - - this.configMin = min; - return this; - } - - setGradient (gradient) { - this.gradient = gradientMapper(gradient); - return this; - } - - setTranslate (translate) { - if (translate.constructor !== Array) { - throw new Error('Invalid Translate: Translate has to be of Array type'); - } - if (translate.length !== 2) { - throw new Error('Translate has to be of length 2'); - } - this.translate = translate; - return this; - }; - - setZoom (zoom) { - if (isNullUndefined(zoom) || isNotNumber(zoom)) { - throw new Error('Invalid zoom: Expected Number'); - } - - this.zoom = zoom; - return this; - }; - - setRotationAngle (angle) { - if (isNullUndefined(angle) || isNotNumber(angle)) { - throw new Error('Invalid Angle: Expected Number'); - } - - this.angle = angle; - return this; - }; - - setSize (size) { - if (isNullUndefined(size) || isNotNumber(size)) { - throw new Error('Invalid Size: Expected Number'); - } - - this.size = size; - return this; - }; - - setIntensity (intensity) { - if (isNullUndefined(intensity) || isNotNumber(intensity)) { - this.intensity = 1.0; // applying default intensity - throw new Error('Invalid Intensity: Expected Number'); - } - - if (intensity > 1 || intensity < 0) { - this.intensity = intensity > 1 ? 1 : 0; // Setting bound value - throw new Error('Invalid Intensity value ' + intensity); - } - this.intensity = intensity; - return this; - }; - - setOpacity (opacity) { - if (isNullUndefined(opacity) || isNotNumber(opacity)) { - throw new Error('Invalid Opacity: Expected Number'); - } - - if (opacity > 1 || opacity < 0) { - throw new Error('Invalid Opacity value ' + opacity); - } - this.opacity = opacity; - return this; - }; - - setBackgroundImage (config) { - const self = this; - if (!config.url) { - return; - } - - const maxTextureSize = this.ctx.getParameter(this.ctx.MAX_TEXTURE_SIZE); - this.imageTexture = this.ctx.createTexture(); - this.type = 'TEXTURE_2D'; - this.imageConfig = null; - - this.imgWidth = config.width || this.width; - this.imgHeight = config.height || this.height; - - this.imgWidth = this.imgWidth > maxTextureSize ? maxTextureSize : this.imgWidth; - this.imgHeight = this.imgHeight > maxTextureSize ? maxTextureSize : this.imgHeight; - - imageInstance(config.url, function onUpdateCallBack () { - self.ctx.activeTexture(self.ctx.TEXTURE0); - self.ctx.bindTexture(self.ctx.TEXTURE_2D, self.imageTexture); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_S, self.ctx.CLAMP_TO_EDGE); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_WRAP_T, self.ctx.CLAMP_TO_EDGE); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MIN_FILTER, self.ctx.LINEAR); - self.ctx.texParameteri(self.ctx.TEXTURE_2D, self.ctx.TEXTURE_MAG_FILTER, self.ctx.LINEAR); - - self.ctx.texImage2D( - self.ctx.TEXTURE_2D, - 0, - self.ctx.RGBA, - this.naturalWidth, - this.naturalHeight, - 0, - self.ctx.RGBA, - self.ctx.UNSIGNED_BYTE, - this - ); - - self.imageConfig = { - x: config.x || 0, - y: config.y || 0, - height: self.imgHeight, - width: self.imgWidth, - image: this - }; - - self.render(); - }, function onErrorCallBack (error) { - throw new Error('Image Load Error', error); - }); - return this; - }; - - clearData () { - this.heatmapData = []; - this.hearmapExData = {}; - this.render(); - }; - - addData (data, transIntactFlag) { - const self = this; - for (let i = 0; i < data.length; i++) { - if (transIntactFlag) { - transCoOr.call(self, data[i]); - } - this.heatmapData.push(data[i]); - } - this.renderData(this.heatmapData); - return this; - }; - - renderData (data) { - if (data.constructor !== Array) { - throw new Error('Expected Array type'); - } - this.hearmapExData = extractData(data, this); - this.heatmapData = data; - this.render(); - return this; - }; - - render () { - renderExec.call(this); - }; - - projection (data) { - // Pre-compute constants and repetitive calculations - const zoomFactor = this.zoom || 0.1; - const halfWidth = this.width / 2; - const halfHeight = this.height / 2; - const translateX = this.translate[0]; - const translateY = this.translate[1]; - const angle = this.angle; - const aspect = this.width / this.height; - - // Calculate the adjusted positions - let posX = (data.x + translateX - halfWidth) / (halfWidth * zoomFactor); - let posY = (data.y + translateY - halfHeight) / (halfHeight * zoomFactor); - - posX *= aspect; - - // Rotate the point if there's an angle - if (angle !== 0.0) { - const cosAngle = Math.cos(-angle); - const sinAngle = Math.sin(-angle); - const xNew = (cosAngle * posX) - (sinAngle * posY); - posY = (sinAngle * posX) + (cosAngle * posY); - posX = xNew; - } - - posX *= 1.0 / aspect; - - // Scale back and adjust the position - posX = (posX * halfWidth) + halfWidth; - posY = (posY * halfHeight) + halfHeight; - - return { x: posX, y: posY }; - }; -} diff --git a/src/heatmap.ts b/src/heatmap.ts new file mode 100644 index 0000000..f8becdb --- /dev/null +++ b/src/heatmap.ts @@ -0,0 +1,178 @@ +// Internal class that encapsulates private properties and methods + +import { HeatmapRenderer } from "./heatmapRenderer"; +import { + BackgroundImageConfig, + GradientElement, + HeatmapConfig, + Point, + Translate, +} from "./types"; + +export class Heatmap { + private renderer: HeatmapRenderer; + ctx; + ratio; + width; + height; + min; + max; + size; + zoom; + angle; + intensity; + translate; + opacity; + gradient; + imageConfig; + + constructor(context: string | HTMLElement, config: HeatmapConfig) { + this.renderer = new HeatmapRenderer(context, config); + this.ctx = this.renderer.ctx; + this.ratio = this.renderer.ratio; + this.width = this.renderer.width; + this.height = this.renderer.height; + this.min = this.renderer.min; + this.max = this.renderer.max; + this.size = this.renderer.size; + this.zoom = this.renderer.zoom; + this.angle = this.renderer.angle; + this.intensity = this.renderer.intensity; + this.translate = this.renderer.translate; + this.opacity = this.renderer.opacity; + this.gradient = this.renderer.gradient; + this.imageConfig = this.renderer.imageConfig; + } + + /** + * Set the maximum data value for relative gradient calculations + * @param max - number + * @returns instance + */ + setMax(max: number) { + return this.renderer.setMax(max); + } + + /** + * Set the minimum data value for relative gradient calculations + * @param min - number + * @returns instance + */ + setMin(min: number) { + return this.renderer.setMin(min); + } + + /** + * Accepts array of objects with color value and offset + * @param gradient - Color Gradient + * @returns instance + */ + setGradient(gradient: GradientElement[]) { + return this.renderer.setGradient(gradient); + } + + /** + * Set the translate transformation on the canvas + * @param translate - Accepts array [x, y] + * @returns instance + */ + setTranslate(translate: Translate) { + return this.renderer.setTranslate(translate); + } + + /** + * Set the zoom transformation on the canvas + * @param zoom - Accepts float value + * @returns instance + */ + setZoom(zoom: number) { + return this.renderer.setZoom(zoom); + } + + /** + * Set the rotation transformation on the canvas + * @param angle - Accepts angle in radians + * @returns instance + */ + setRotationAngle(angle: number) { + return this.renderer.setRotationAngle(angle); + } + + /** + * Set the point radius + * @param size - Accepts float value + * @returns instance + */ + setSize(size: number) { + return this.renderer.setSize(size); + } + + /** + * Set the intensity factor + * @param intensity - Accepts float value + * @returns instance + */ + setIntensity(intensity: number) { + return this.renderer.setIntensity(intensity); + } + + /** + * Set the opacity factor + * @param opacity - The opacity factor. + * @returns instance + */ + setOpacity(opacity: number) { + return this.renderer.setOpacity(opacity); + } + + /** + * Set the background image + * @param config - Accepts Object with { Url, height, width, x, and y} properties + * @returns instance + */ + setBackgroundImage(config: BackgroundImageConfig) { + return this.renderer.setBackgroundImage(config); + } + + /** + * After adding data points, need to invoke .render() method to update the heatmap + * @param data - The data points with 'x', 'y' and 'value' + * @param transIntactFlag - Flag indicating whether to apply existing heatmap transformations on the newly added data points + * @returns instance + */ + addData(data: Point[], transIntactFlag: boolean) { + return this.renderer.addData(data, transIntactFlag); + } + + /** + * @param data - Accepts an array of data points with 'x', 'y' and 'value' + * @returns instance + */ + renderData(data: Point[]) { + return this.renderer.renderData(data); + } + + /** + * Method to re-render the heatmap. This method needs to be invoked as and when configurations get changed + */ + render() { + this.renderer.render(); + } + + /** + * Get projected co-ordinates relative to the heatmap layer + * @param data - The data point to project. + * @returns projected data point. + */ + + projection(data: Point) { + return this.renderer.projection(data); + } + + /** + * Clears canvas + */ + clear() { + this.renderer.clear(); + } +} diff --git a/src/heatmapRenderer.ts b/src/heatmapRenderer.ts new file mode 100644 index 0000000..6bbaa78 --- /dev/null +++ b/src/heatmapRenderer.ts @@ -0,0 +1,686 @@ +import { GradShader, ColorShader, ImageShader } from "./shaders"; +import { + BackgroundImageConfig, + GradientElement, + HearmapExData, + HeatmapConfig, + MappedGradient, + Point, + ShaderProgram, + Translate, +} from "./types"; +import { + createImageShader, + createGradiantShader, + createColorShader, +} from "./utils/shaderUtils"; +import { + isNullUndefined, + isNotNumber, + isSortedAscending, + getPixelRatio, +} from "./utils/utils"; + +function gradientMapper(grad: GradientElement[]): MappedGradient { + if (!Array.isArray(grad) || grad.length < 2) { + throw new Error( + "Invalid gradient: Expected an array with at least 2 elements." + ); + } + + if (!isSortedAscending(grad)) { + throw new Error("Invalid gradient: Gradient is not sorted"); + } + + const gradLength = grad.length; + const values = new Float32Array(gradLength * 4); + const offsets = new Array(gradLength); + + grad.forEach(function (d, i) { + const baseIndex = i * 4; + values[baseIndex] = d.color[0] / 255; + values[baseIndex + 1] = d.color[1] / 255; + values[baseIndex + 2] = d.color[2] / 255; + values[baseIndex + 3] = d.color[3] !== undefined ? d.color[3] : 1.0; + offsets[i] = d.offset; + }); + + return { + value: values, + length: gradLength, + offset: offsets, + }; +} + +function extractData(data: Point[], self: HeatmapRenderer): HearmapExData { + const len = data.length; + let { posVec = new Float32Array(), rVec = new Float32Array() } = + (self.hearmapExData || {}) as HearmapExData; + + if (self.pLen !== len) { + self.buffer = new ArrayBuffer(len * 8); + posVec = new Float32Array(self.buffer); + self.buffer2 = new ArrayBuffer(len * 4); + rVec = new Float32Array(self.buffer2); + self.pLen = len; + } + + const dataMinMaxValue = { + min: Infinity, + max: -Infinity, + }; + for (let i = 0; i < len; i++) { + posVec[i * 2] = data[i].x; + posVec[i * 2 + 1] = data[i].y; + rVec[i] = data[i].value; + if (dataMinMaxValue.min > data[i].value) { + dataMinMaxValue.min = data[i].value; + } + if (dataMinMaxValue.max < data[i].value) { + dataMinMaxValue.max = data[i].value; + } + } + + return { + posVec: posVec as Float32Array, + rVec: rVec as Float32Array, + minMax: dataMinMaxValue, + }; +} + +function transCoOr(this: HeatmapRenderer, data: Point) { + const zoomFactor = this.zoom || 0.1; + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + const { angle, translate } = this; + + // Combine operations to reduce the number of arithmetic steps + let posX = ((data.x - halfWidth) / halfWidth) * zoomFactor; + let posY = ((data.y - halfHeight) / halfHeight) * zoomFactor; + + // Rotate the point if there's an angle + if (angle !== 0.0) { + const cosAngle = Math.cos(angle); + const sinAngle = Math.sin(angle); + posY = sinAngle * posX + cosAngle * posY; + posX = cosAngle * posX - sinAngle * posY; + } + + // Scale back and adjust the position + posX = posX * halfWidth + halfWidth - translate[0]; + posY = posY * halfHeight + halfHeight - translate[1]; + + data.x = posX; + data.y = posY; + + return { x: posX, y: posY }; +} + +function renderExec(this: HeatmapRenderer) { + const ctx = this.ctx; + + if (!ctx) { + return; + } + + ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); + + ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); + ctx.texImage2D( + ctx.TEXTURE_2D, + 0, + ctx.RGBA, + this.width * this.ratio, + this.height * this.ratio, + 0, + ctx.RGBA, + ctx.UNSIGNED_BYTE, + null + ); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); + + ctx.bindFramebuffer(ctx.FRAMEBUFFER, this.fbo); + ctx.framebufferTexture2D( + ctx.FRAMEBUFFER, + ctx.COLOR_ATTACHMENT0, + ctx.TEXTURE_2D, + this.fbTexObj, + 0 + ); + + if (this.hearmapExData) { + renderHeatGrad.call(this, ctx, this.hearmapExData as HearmapExData); + } + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + if (this.imageConfig) { + renderImage.call(this, ctx, this.imageConfig); + } + renderColorGradiant.call(this, ctx); +} + +function renderHeatGrad( + this: HeatmapRenderer, + ctx: WebGL2RenderingContext, + exData: HearmapExData +) { + ctx.useProgram(this.gradShadOP.program); + + this.min = + this.configMin !== null ? this.configMin : exData?.minMax?.min ?? 0; + this.max = + this.configMax !== null ? this.configMax : exData?.minMax?.max ?? 0; + this.gradShadOP.attr[0].data = exData.posVec || []; + this.gradShadOP.attr[1].data = exData.rVec || []; + + ctx.uniform2fv( + this.gradShadOP.uniform.u_resolution, + new Float32Array([this.width * this.ratio, this.height * this.ratio]) + ); + ctx.uniform2fv( + this.gradShadOP.uniform.u_translate, + new Float32Array([this.translate[0], this.translate[1]]) + ); + ctx.uniform1f(this.gradShadOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); + ctx.uniform1f(this.gradShadOP.uniform.u_angle, this.angle); + ctx.uniform1f(this.gradShadOP.uniform.u_density, this.ratio); + ctx.uniform1f(this.gradShadOP.uniform.u_max, this.max); + ctx.uniform1f(this.gradShadOP.uniform.u_min, this.min); + ctx.uniform1f(this.gradShadOP.uniform.u_size, this.size); + ctx.uniform1f(this.gradShadOP.uniform.u_intensity, this.intensity); + + this.gradShadOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + + ctx.drawArrays(ctx.POINTS, 0, (exData.posVec || []).length / 2); +} + +function renderImage( + this: HeatmapRenderer, + ctx: WebGL2RenderingContext, + imageConfig: BackgroundImageConfig +) { + const { x = 0, y = 0, width = 0, height = 0 } = imageConfig; + + ctx.useProgram(this.imageShaOP.program); + + ctx.uniform2fv( + this.imageShaOP.uniform.u_resolution, + new Float32Array([this.width * this.ratio, this.height * this.ratio]) + ); + ctx.uniform2fv( + this.imageShaOP.uniform.u_translate, + new Float32Array([this.translate[0], this.translate[1]]) + ); + ctx.uniform1f(this.imageShaOP.uniform.u_zoom, this.zoom ? this.zoom : 0.01); + ctx.uniform1f(this.imageShaOP.uniform.u_angle, this.angle); + ctx.uniform1f(this.imageShaOP.uniform.u_density, this.ratio); + + this.imageShaOP.attr[0].data = new Float32Array([ + x, + y, + x + width, + y, + x, + y + height, + x, + y + height, + x + width, + y, + x + width, + y + height, + ]); + + this.imageShaOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + + ctx.uniform1i(this.imageShaOP.uniform.u_image, 0); + ctx.activeTexture(this.ctx!.TEXTURE0); + ctx.bindTexture(this.ctx!.TEXTURE_2D, this.imageTexture); + ctx.drawArrays(ctx.TRIANGLES, 0, 6); +} + +function renderColorGradiant( + this: HeatmapRenderer, + ctx: WebGL2RenderingContext +) { + ctx.useProgram(this.colorShadOP.program); + + ctx.uniform4fv(this.colorShadOP.uniform.u_colorArr, this.gradient!.value); + ctx.uniform1f(this.colorShadOP.uniform.u_colorCount, this.gradient!.length); + ctx.uniform1fv( + this.colorShadOP.uniform.u_offset, + new Float32Array(this.gradient!.offset) + ); + ctx.uniform1f(this.colorShadOP.uniform.u_opacity, this.opacity); + + this.colorShadOP.attr.forEach(function (d) { + ctx.bindBuffer(d.bufferType, d.buffer); + ctx.bufferData(d.bufferType, d.data, d.drawType); + ctx.enableVertexAttribArray(d.attribute); + ctx.vertexAttribPointer(d.attribute, d.size, d.valueType, true, 0, 0); + }); + + ctx.uniform1i(this.colorShadOP.uniform.u_framebuffer, 0); + ctx.activeTexture(ctx.TEXTURE0); + ctx.bindTexture(ctx.TEXTURE_2D, this.fbTexObj); + + ctx.drawArrays(ctx.TRIANGLES, 0, 6); +} + +function imageInstance( + url: string, + onLoad: () => void, + onError: OnErrorEventHandler +) { + const imageIns = new Image(); + imageIns.crossOrigin = "anonymous"; + imageIns.onload = onLoad; + imageIns.onerror = onError; + imageIns.src = url; + return imageIns; +} + +export class HeatmapRenderer { + ctx: WebGL2RenderingContext | null = null; + ratio: number = 1; + width: number = 0; + height: number = 0; + imageConfig: BackgroundImageConfig | null = null; + configMin: number | null = null; + configMax: number | null = null; + min: number = 0; + max: number = 0; + hearmapExData: HearmapExData | object = {}; + + gradShadOP!: ShaderProgram; + colorShadOP!: ShaderProgram; + imageShaOP!: ShaderProgram; + fbTexObj!: WebGLTexture; + fbo!: WebGLFramebuffer; + size: number = 0; + zoom: number = 0; + angle: number = 0; + intensity: number = 0; + translate: [number, number] = [0, 0]; + opacity: number = 0; + gradient: MappedGradient | null = null; + imageTexture: WebGLTexture | null = null; + pLen: number | undefined = undefined; + buffer: ArrayBuffer | undefined = undefined; + buffer2: ArrayBuffer | undefined = undefined; + + private layer!: HTMLCanvasElement; + private dom!: Element; + private imgWidth: number = 0; + private imgHeight: number = 0; + private heatmapData: Point[] = []; + private type: string = ""; + + constructor(container: string | HTMLElement, config: HeatmapConfig) { + try { + const res = + typeof container === "string" + ? document.querySelector(container) + : container instanceof HTMLElement + ? container + : null; + if (!res) { + throw new Error("Context must be either a string or an Element"); + } + const { clientHeight: height, clientWidth: width } = res; + const layer = document.createElement("canvas"); + const ctx = layer.getContext("webgl2", { + premultipliedAlpha: false, + depth: false, + antialias: true, + alpha: true, + preserveDrawingBuffer: false, + }) as WebGL2RenderingContext; + + this.ratio = getPixelRatio(ctx); + ctx.clearColor(0, 0, 0, 0); + ctx.enable(ctx.BLEND); + ctx.blendEquation(ctx.FUNC_ADD); + ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); + ctx.depthMask(true); + layer.setAttribute("height", (height * this.ratio).toString()); + layer.setAttribute("width", (width * this.ratio).toString()); + layer.style.height = `${height}px`; + layer.style.width = `${width}px`; + layer.style.position = "absolute"; + res.appendChild(layer); + + this.ctx = ctx; + this.width = width; + this.height = height; + this.imageConfig = null; + this.configMin = null; + this.configMax = null; + this.hearmapExData = {}; + this.layer = layer; + this.dom = res; + this.gradShadOP = createGradiantShader(this.ctx, GradShader); + this.colorShadOP = createColorShader(this.ctx, ColorShader); + this.imageShaOP = createImageShader(this.ctx, ImageShader); + this.fbTexObj = ctx.createTexture()!; + this.fbo = ctx.createFramebuffer()!; + + if (!isNullUndefined(config.size)) { + this.setSize(config.size); + } else { + this.size = 20.0; + } + + if (!isNullUndefined(config.max)) { + this.setMax(config.max); + } else { + this.configMax = null; + } + + if (!isNullUndefined(config.min)) { + this.setMin(config.min); + } else { + this.configMin = null; + } + + if (!isNullUndefined(config.intensity)) { + this.setIntensity(config.intensity); + } else { + this.intensity = 1.0; + } + + if (!isNullUndefined(config.translate)) { + this.setTranslate(config.translate); + } else { + this.translate = [0, 0]; + } + + if (!isNullUndefined(config.zoom)) { + this.setZoom(config.zoom); + } else { + this.zoom = 1.0; + } + + if (!isNullUndefined(config.angle)) { + this.setRotationAngle(config.angle); + } else { + this.angle = 0.0; + } + + if (!isNullUndefined(config.opacity)) { + this.setOpacity(config.opacity); + } else { + this.opacity = 1.0; + } + + this.gradient = gradientMapper(config.gradient); + + if (config.backgroundImage && config.backgroundImage.url) { + this.setBackgroundImage(config.backgroundImage); + } + + this.heatmapData = []; + + this.ctx.viewport(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + } catch (error) { + console.error(error); + } + } + + resize() { + const height = this.dom.clientHeight; + const width = this.dom.clientWidth; + this.layer.setAttribute("height", (height * this.ratio).toString()); + this.layer.setAttribute("width", (width * this.ratio).toString()); + this.layer.style.height = `${height}px`; + this.layer.style.width = `${width}px`; + this.width = width; + this.height = height; + this.ctx!.viewport(0, 0, this.ctx!.canvas.width, this.ctx!.canvas.height); + /* Perform update */ + this.render(); + } + + clear() { + this.ctx!.clear(this.ctx!.COLOR_BUFFER_BIT | this.ctx!.DEPTH_BUFFER_BIT); + } + + setMax(max: number): HeatmapRenderer { + if (isNullUndefined(max) || isNotNumber(max)) { + throw new Error("Invalid max: Expected Number"); + } + + this.configMax = max; + return this; + } + + setMin(min: number): HeatmapRenderer { + if (isNullUndefined(min) || isNotNumber(min)) { + throw new Error("Invalid min: Expected Number"); + } + + this.configMin = min; + return this; + } + + setGradient(gradient: GradientElement[]): HeatmapRenderer { + this.gradient = gradientMapper(gradient); + return this; + } + + setTranslate(translate: Translate) { + if (translate.constructor !== Array) { + throw new Error("Invalid Translate: Translate has to be of Array type"); + } + if (translate.length !== 2) { + throw new Error("Translate has to be of length 2"); + } + this.translate = translate; + return this; + } + + setZoom(zoom: number): HeatmapRenderer { + if (isNullUndefined(zoom) || isNotNumber(zoom)) { + throw new Error("Invalid zoom: Expected Number"); + } + + this.zoom = zoom; + return this; + } + + setRotationAngle(angle: number): HeatmapRenderer { + if (isNullUndefined(angle) || isNotNumber(angle)) { + throw new Error("Invalid Angle: Expected Number"); + } + + this.angle = angle; + return this; + } + + setSize(size: number): HeatmapRenderer { + if (isNullUndefined(size) || isNotNumber(size)) { + throw new Error("Invalid Size: Expected Number"); + } + + this.size = size; + return this; + } + + setIntensity(intensity: number): HeatmapRenderer { + if (isNullUndefined(intensity) || isNotNumber(intensity)) { + this.intensity = 1.0; // applying default intensity + throw new Error("Invalid Intensity: Expected Number"); + } + + if (intensity > 1 || intensity < 0) { + this.intensity = intensity > 1 ? 1 : 0; // Setting bound value + throw new Error("Invalid Intensity value " + intensity); + } + this.intensity = intensity; + return this; + } + + setOpacity(opacity: number): HeatmapRenderer { + if (isNullUndefined(opacity) || isNotNumber(opacity)) { + throw new Error("Invalid Opacity: Expected Number"); + } + + if (opacity > 1 || opacity < 0) { + throw new Error("Invalid Opacity value " + opacity); + } + this.opacity = opacity; + return this; + } + + setBackgroundImage(config: BackgroundImageConfig) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + if (!config.url) { + return; + } + + const maxTextureSize = this.ctx!.getParameter(this.ctx!.MAX_TEXTURE_SIZE); + this.imageTexture = this.ctx!.createTexture(); + this.type = "TEXTURE_2D"; + this.imageConfig = null; + + this.imgWidth = config.width || this.width; + this.imgHeight = config.height || this.height; + + this.imgWidth = + this.imgWidth > maxTextureSize ? maxTextureSize : this.imgWidth; + this.imgHeight = + this.imgHeight > maxTextureSize ? maxTextureSize : this.imgHeight; + + imageInstance( + config.url, + function onUpdateCallBack(this: HTMLImageElement) { + self.ctx!.activeTexture(self.ctx!.TEXTURE0); + self.ctx!.bindTexture(self.ctx!.TEXTURE_2D, self.imageTexture); + self.ctx!.texParameteri( + self.ctx!.TEXTURE_2D, + self.ctx!.TEXTURE_WRAP_S, + self.ctx!.CLAMP_TO_EDGE + ); + self.ctx!.texParameteri( + self.ctx!.TEXTURE_2D, + self.ctx!.TEXTURE_WRAP_T, + self.ctx!.CLAMP_TO_EDGE + ); + self.ctx!.texParameteri( + self.ctx!.TEXTURE_2D, + self.ctx!.TEXTURE_MIN_FILTER, + self.ctx!.LINEAR + ); + self.ctx!.texParameteri( + self.ctx!.TEXTURE_2D, + self.ctx!.TEXTURE_MAG_FILTER, + self.ctx!.LINEAR + ); + + self.ctx!.texImage2D( + self.ctx!.TEXTURE_2D, + 0, + self.ctx!.RGBA, + this.naturalWidth, + this.naturalHeight, + 0, + self.ctx!.RGBA, + self.ctx!.UNSIGNED_BYTE, + this + ); + + self.imageConfig = { + x: config.x || 0, + y: config.y || 0, + height: self.imgHeight, + width: self.imgWidth, + image: this, + }; + + self.render(); + }, + function onErrorCallBack(error) { + throw new Error(`Image Load Error, ${error}`); + } + ); + return this; + } + + clearData() { + this.heatmapData = []; + this.hearmapExData = {}; + this.render(); + } + + addData(data: Point[], transIntactFlag: boolean): HeatmapRenderer { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + for (let i = 0; i < data.length; i++) { + if (transIntactFlag) { + transCoOr.call(self, data[i]); + } + this.heatmapData.push(data[i]); + } + this.renderData(this.heatmapData); + return this; + } + + renderData(data: Point[]): HeatmapRenderer { + if (data.constructor !== Array) { + throw new Error("Expected Array type"); + } + this.hearmapExData = extractData(data, this); + this.heatmapData = data; + this.render(); + return this; + } + + render() { + renderExec.call(this); + } + + projection(data: Point) { + // Pre-compute constants and repetitive calculations + const zoomFactor = this.zoom || 0.1; + const halfWidth = this.width / 2; + const halfHeight = this.height / 2; + const translateX = this.translate[0]; + const translateY = this.translate[1]; + const angle = this.angle; + const aspect = this.width / this.height; + + // Calculate the adjusted positions + let posX = (data.x + translateX - halfWidth) / (halfWidth * zoomFactor); + let posY = (data.y + translateY - halfHeight) / (halfHeight * zoomFactor); + + posX *= aspect; + + // Rotate the point if there's an angle + if (angle !== 0.0) { + const cosAngle = Math.cos(-angle); + const sinAngle = Math.sin(-angle); + const xNew = cosAngle * posX - sinAngle * posY; + posY = sinAngle * posX + cosAngle * posY; + posX = xNew; + } + + posX *= 1.0 / aspect; + + // Scale back and adjust the position + posX = posX * halfWidth + halfWidth; + posY = posY * halfHeight + halfHeight; + + return { x: posX, y: posY }; + } +} diff --git a/src/main.js b/src/main.js deleted file mode 100644 index 929b80a..0000000 --- a/src/main.js +++ /dev/null @@ -1,6 +0,0 @@ - -import { HeatmapRenderer } from './heatmap.js'; - -export default function Heatmap (context, config = {}) { - return new HeatmapRenderer(context, config); -} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..74b928a --- /dev/null +++ b/src/main.ts @@ -0,0 +1,6 @@ +import { Heatmap } from "./heatmap"; +import { HeatmapConfig } from "./types"; + +export default function (context: string | HTMLElement, config: HeatmapConfig) { + return new Heatmap(context, config); +} diff --git a/src/shaders.js b/src/shaders.ts similarity index 99% rename from src/shaders.js rename to src/shaders.ts index 6b1dec8..11f51f1 100644 --- a/src/shaders.js +++ b/src/shaders.ts @@ -44,7 +44,7 @@ export const GradShader = { if(r <= 1.0) { fragColor = vec4(0, 0, 0, ((v_i - u_min) / (deno)) * u_intensity * (1.0 - sqrt(r))); } - }` + }`, }; export const ColorShader = { @@ -99,7 +99,7 @@ export const ColorShader = { fragColor = vec4(0.0, 0.0, 0.0, 0.0); } } - ` + `, }; export const ImageShader = { @@ -146,5 +146,5 @@ export const ImageShader = { void main() { fragColor = texture(u_image, v_texCoord); } - ` + `, }; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..e89c12b --- /dev/null +++ b/src/types.ts @@ -0,0 +1,81 @@ +export type JavaScriptDataType = + | number + | string + | boolean + | null + | undefined + | symbol + | bigint + | object; + +export type ShaderTypes = "VERTEX_SHADER" | "FRAGMENT_SHADER"; + +export type Shader = { vertex: string; fragment: string }; + +export interface ShaderProgram { + program: WebGLProgram; + attr: { + bufferType: GLenum; + buffer: WebGLBuffer; + drawType: GLenum; + valueType: GLenum; + size: GLint; + attribute: number; + data: Float32Array; + }[]; + uniform: { + [key: string]: WebGLUniformLocation | null; + }; +} + +export type Color = [number, number, number, number?]; + +export interface GradientElement { + color: Color; + offset: number; +} + +export interface MappedGradient { + value: Float32Array; + length: number; + offset: number[]; +} + +export interface Point { + x: number; + y: number; + value: number; +} + +export type HeatmapConfig = { + size?: number; + max?: number; + min?: number; + intensity?: number; + translate?: [number, number]; + zoom?: number; + angle?: number; + opacity?: number; + gradient: GradientElement[]; + backgroundImage?: BackgroundImageConfig; +}; + +export type HearmapExData = { + posVec: Float32Array; + rVec: Float32Array; + minMax: { + min: number; + max: number; + }; +}; + +export interface BackgroundImageConfig { + url?: string; + width?: number; + height?: number; + x: number; + y: number; + image?: HTMLImageElement; +} + +export type Translate = [number, number]; diff --git a/src/utils/shaderUtils.js b/src/utils/shaderUtils.js deleted file mode 100644 index 8e9856d..0000000 --- a/src/utils/shaderUtils.js +++ /dev/null @@ -1,123 +0,0 @@ -function createShader (ctx, type, src) { - var shader = ctx.createShader(ctx[type]); - ctx.shaderSource(shader, src); - ctx.compileShader(shader); - var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); - if (!compiled) { - var lastError = ctx.getShaderInfoLog(shader); - ctx.deleteShader(shader); - throw new Error("*** Error compiling shader '" + shader + "':" + lastError); - } - return shader; -} - -function createProgram (ctx, shader) { - var vshader = createShader(ctx, 'VERTEX_SHADER', shader.vertex); - var fshader = createShader(ctx, 'FRAGMENT_SHADER', shader.fragment); - - var program = ctx.createProgram(); - - ctx.attachShader(program, vshader); - ctx.attachShader(program, fshader); - ctx.linkProgram(program); - - var linked = ctx.getProgramParameter(program, ctx.LINK_STATUS); - if (!linked) { - var lastError = ctx.getProgramInfoLog(program); - ctx.deleteProgram(program); - throw new Error('Error in program linking:' + lastError); - } else { - return program; - } -} - - -export const createImageShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_position'), - data: new Float32Array([]) - }, { - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_texCoord'), - data: new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]) - }], - uniform: { - u_resolution: ctx.getUniformLocation(program, 'u_resolution'), - u_image: ctx.getUniformLocation(program, 'u_image'), - u_translate: ctx.getUniformLocation(program, 'u_translate'), - u_zoom: ctx.getUniformLocation(program, 'u_zoom'), - u_angle: ctx.getUniformLocation(program, 'u_angle'), - u_density: ctx.getUniformLocation(program, 'u_density') - } - }; -}; - -export const createGradiantShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_position'), - data: new Float32Array([]) - }, { - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 1, - attribute: ctx.getAttribLocation(program, 'a_intensity'), - data: new Float32Array([]) - }], - uniform: { - u_resolution: ctx.getUniformLocation(program, 'u_resolution'), - u_max: ctx.getUniformLocation(program, 'u_max'), - u_min: ctx.getUniformLocation(program, 'u_min'), - u_size: ctx.getUniformLocation(program, 'u_size'), - u_intensity: ctx.getUniformLocation(program, 'u_intensity'), - u_translate: ctx.getUniformLocation(program, 'u_translate'), - u_zoom: ctx.getUniformLocation(program, 'u_zoom'), - u_angle: ctx.getUniformLocation(program, 'u_angle'), - u_density: ctx.getUniformLocation(program, 'u_density') - } - }; -}; - -export const createColorShader = function (ctx, shader) { - var program = createProgram(ctx, shader); - return { - program: program, - attr: [{ - bufferType: ctx.ARRAY_BUFFER, - buffer: ctx.createBuffer(), - drawType: ctx.STATIC_DRAW, - valueType: ctx.FLOAT, - size: 2, - attribute: ctx.getAttribLocation(program, 'a_texCoord'), - data: new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]) - }], - uniform: { - u_framebuffer: ctx.getUniformLocation(program, 'u_framebuffer'), - u_colorArr: ctx.getUniformLocation(program, 'u_colorArr'), - u_colorCount: ctx.getUniformLocation(program, 'u_colorCount'), - u_opacity: ctx.getUniformLocation(program, 'u_opacity'), - u_offset: ctx.getUniformLocation(program, 'u_offset') - } - }; -}; diff --git a/src/utils/shaderUtils.ts b/src/utils/shaderUtils.ts new file mode 100644 index 0000000..c9302f5 --- /dev/null +++ b/src/utils/shaderUtils.ts @@ -0,0 +1,185 @@ +import { Shader, ShaderProgram, ShaderTypes } from "../types"; + +function createShader( + ctx: WebGL2RenderingContext, + type: ShaderTypes, + src: string +) { + const shader = ctx.createShader(ctx[type]); + + if (!shader) { + throw new Error("Failed to create shader."); + } + + ctx.shaderSource(shader, src); + ctx.compileShader(shader); + const compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); + if (!compiled) { + const lastError = ctx.getShaderInfoLog(shader); + ctx.deleteShader(shader); + throw new Error("*** Error compiling shader '" + shader + "':" + lastError); + } + return shader; +} + +function createProgram( + ctx: WebGL2RenderingContext, + shader: Shader +): WebGLProgram { + const vshader = createShader(ctx, "VERTEX_SHADER", shader.vertex); + const fshader = createShader(ctx, "FRAGMENT_SHADER", shader.fragment); + + const program = ctx.createProgram(); + + if (!program) { + throw new Error("Failed to create program."); + } + + ctx.attachShader(program, vshader); + ctx.attachShader(program, fshader); + ctx.linkProgram(program); + + const linked = ctx.getProgramParameter(program, ctx.LINK_STATUS); + if (!linked) { + const lastError = ctx.getProgramInfoLog(program); + ctx.deleteProgram(program); + throw new Error("Error in program linking:" + lastError); + } else { + return program; + } +} + +export const createImageShader = function ( + ctx: WebGL2RenderingContext, + shader: Shader +): ShaderProgram { + const program = createProgram(ctx, shader); + + const positionBuffer = ctx.createBuffer(); + if (!positionBuffer) { + throw new Error("Failed to create position buffer."); + } + const texCoordBuffer = ctx.createBuffer(); + if (!texCoordBuffer) { + throw new Error("Failed to create texture coordinate buffer."); + } + + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: positionBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_position"), + data: new Float32Array([]), + }, + { + bufferType: ctx.ARRAY_BUFFER, + buffer: texCoordBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_texCoord"), + data: new Float32Array([ + 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, + ]), + }, + ], + uniform: { + u_resolution: ctx.getUniformLocation(program, "u_resolution"), + u_image: ctx.getUniformLocation(program, "u_image"), + u_translate: ctx.getUniformLocation(program, "u_translate"), + u_zoom: ctx.getUniformLocation(program, "u_zoom"), + u_angle: ctx.getUniformLocation(program, "u_angle"), + u_density: ctx.getUniformLocation(program, "u_density"), + }, + }; +}; + +export const createGradiantShader = function ( + ctx: WebGL2RenderingContext, + shader: Shader +): ShaderProgram { + const program = createProgram(ctx, shader); + + const positionBuffer = ctx.createBuffer(); + if (!positionBuffer) { + throw new Error("Failed to create position buffer."); + } + const intensityBuffer = ctx.createBuffer(); + if (!intensityBuffer) { + throw new Error("Failed to create intensity buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: positionBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_position"), + data: new Float32Array([]), + }, + { + bufferType: ctx.ARRAY_BUFFER, + buffer: intensityBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 1, + attribute: ctx.getAttribLocation(program, "a_intensity"), + data: new Float32Array([]), + }, + ], + uniform: { + u_resolution: ctx.getUniformLocation(program, "u_resolution"), + u_max: ctx.getUniformLocation(program, "u_max"), + u_min: ctx.getUniformLocation(program, "u_min"), + u_size: ctx.getUniformLocation(program, "u_size"), + u_intensity: ctx.getUniformLocation(program, "u_intensity"), + u_translate: ctx.getUniformLocation(program, "u_translate"), + u_zoom: ctx.getUniformLocation(program, "u_zoom"), + u_angle: ctx.getUniformLocation(program, "u_angle"), + u_density: ctx.getUniformLocation(program, "u_density"), + }, + }; +}; + +export const createColorShader = function ( + ctx: WebGL2RenderingContext, + shader: Shader +): ShaderProgram { + const program = createProgram(ctx, shader); + + const texCoordBuffer = ctx.createBuffer(); + if (!texCoordBuffer) { + throw new Error("Failed to create texture coordinate buffer."); + } + return { + program: program, + attr: [ + { + bufferType: ctx.ARRAY_BUFFER, + buffer: texCoordBuffer, + drawType: ctx.STATIC_DRAW, + valueType: ctx.FLOAT, + size: 2, + attribute: ctx.getAttribLocation(program, "a_texCoord"), + data: new Float32Array([ + 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, + ]), + }, + ], + uniform: { + u_framebuffer: ctx.getUniformLocation(program, "u_framebuffer"), + u_colorArr: ctx.getUniformLocation(program, "u_colorArr"), + u_colorCount: ctx.getUniformLocation(program, "u_colorCount"), + u_opacity: ctx.getUniformLocation(program, "u_opacity"), + u_offset: ctx.getUniformLocation(program, "u_offset"), + }, + }; +}; diff --git a/src/utils/utils.js b/src/utils/utils.js deleted file mode 100644 index 8394133..0000000 --- a/src/utils/utils.js +++ /dev/null @@ -1,27 +0,0 @@ -export function isNullUndefined (val) { - return val === null || val === undefined; -} - -export function isNotNumber (val) { - return typeof val !== 'number'; -} - -export function isSortedAscending (arr) { - for (let i = 0; i < arr.length - 1; i++) { - if (arr[i + 1].offset - arr[i].offset < 0) { - return false; - } - } - return true; -} - -export function getPixlRatio (ctx) { - const dpr = window.devicePixelRatio || 1; - const bsr = ctx.webkitBackingStorePixelRatio || - ctx.mozBackingStorePixelRatio || - ctx.msBackingStorePixelRatio || - ctx.oBackingStorePixelRatio || - ctx.backingStorePixelRatio || 1; - - return dpr / bsr; -} diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..146757c --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,36 @@ +import { JavaScriptDataType } from "../types"; + +export function isNullUndefined(val: unknown): val is null | undefined { + return val === null || val === undefined; +} + +export function isNotNumber( + val: unknown +): val is Exclude { + return typeof val !== "number"; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isSortedAscending(arr: any[]) { + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i + 1].offset - arr[i].offset < 0) { + return false; + } + } + return true; +} + +/** @see https://codereview.chromium.org/156833002/ */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function getPixelRatio(ctx: any) { + const dpr = window.devicePixelRatio || 1; + const bsr = + ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || + 1; + + return dpr / bsr; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a870116 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es2018", + "module": "esnext", + "moduleResolution": "node", + "noEmitOnError": true, + "lib": ["es2022", "DOM"], + "strict": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "emitDeclarationOnly": true + }, + "include": ["./src/**/*.ts"], + "exclude": ["node_modules", "dist"] +}