diff --git a/.eslintrc.json b/.eslintrc.json
index 12f3dcb04..840341043 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -63,6 +63,10 @@
{
"sourceTag": "project:design-system",
"onlyDependOnLibsWithTags": ["*"]
+ },
+ {
+ "sourceTag": "project:node-dist-vis",
+ "onlyDependOnLibsWithTags": ["*"]
}
]
}
diff --git a/apps/node-dist-vis-wc-e2e/.eslintrc.json b/apps/node-dist-vis-wc-e2e/.eslintrc.json
new file mode 100644
index 000000000..696cb8b12
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/.eslintrc.json
@@ -0,0 +1,10 @@
+{
+ "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/node-dist-vis-wc-e2e/cypress.config.ts b/apps/node-dist-vis-wc-e2e/cypress.config.ts
new file mode 100644
index 000000000..7df58bdcf
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/cypress.config.ts
@@ -0,0 +1,7 @@
+import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
+
+import { defineConfig } from 'cypress';
+
+export default defineConfig({
+ e2e: { ...nxE2EPreset(__filename, { cypressDir: 'src' }), baseUrl: 'http://localhost:4200' },
+});
diff --git a/apps/node-dist-vis-wc-e2e/project.json b/apps/node-dist-vis-wc-e2e/project.json
new file mode 100644
index 000000000..1142bc404
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/project.json
@@ -0,0 +1,29 @@
+{
+ "name": "node-dist-vis-wc-e2e",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/node-dist-vis-wc-e2e/src",
+ "tags": [],
+ "implicitDependencies": ["node-dist-vis-wc"],
+ "targets": {
+ "e2e": {
+ "executor": "@nx/cypress:cypress",
+ "options": {
+ "cypressConfig": "apps/node-dist-vis-wc-e2e/cypress.config.ts",
+ "testingType": "e2e",
+ "devServerTarget": "node-dist-vis-wc:serve:development"
+ },
+ "configurations": {
+ "production": {
+ "devServerTarget": "node-dist-vis-wc:serve:production"
+ },
+ "ci": {
+ "devServerTarget": "node-dist-vis-wc:serve-static"
+ }
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ }
+ }
+}
diff --git a/apps/node-dist-vis-wc-e2e/src/e2e/app.cy.ts b/apps/node-dist-vis-wc-e2e/src/e2e/app.cy.ts
new file mode 100644
index 000000000..50275a28d
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/src/e2e/app.cy.ts
@@ -0,0 +1,13 @@
+import { getGreeting } from '../support/app.po';
+
+describe('node-dist-vis-wc-e2e', () => {
+ beforeEach(() => cy.visit('/'));
+
+ it('should display welcome message', () => {
+ // Custom command example, see `../support/commands.ts` file
+ cy.login('my-email@something.com', 'myPassword');
+
+ // Function helper example, see `../support/app.po.ts` file
+ getGreeting().contains(/Welcome/);
+ });
+});
diff --git a/apps/node-dist-vis-wc-e2e/src/fixtures/example.json b/apps/node-dist-vis-wc-e2e/src/fixtures/example.json
new file mode 100644
index 000000000..02e425437
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/src/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+ "name": "Using fixtures to represent data",
+ "email": "hello@cypress.io",
+ "body": "Fixtures are a great way to mock data for responses to routes"
+}
diff --git a/apps/node-dist-vis-wc-e2e/src/support/app.po.ts b/apps/node-dist-vis-wc-e2e/src/support/app.po.ts
new file mode 100644
index 000000000..329342469
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/src/support/app.po.ts
@@ -0,0 +1 @@
+export const getGreeting = () => cy.get('h1');
diff --git a/apps/node-dist-vis-wc-e2e/src/support/commands.ts b/apps/node-dist-vis-wc-e2e/src/support/commands.ts
new file mode 100644
index 000000000..c421a3c47
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/src/support/commands.ts
@@ -0,0 +1,35 @@
+///
+
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+
+// eslint-disable-next-line @typescript-eslint/no-namespace
+declare namespace Cypress {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ interface Chainable {
+ login(email: string, password: string): void;
+ }
+}
+
+// -- This is a parent command --
+Cypress.Commands.add('login', (email, password) => {
+ console.log('Custom command example: Login', email, password);
+});
+//
+// -- This is a child command --
+// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
diff --git a/apps/node-dist-vis-wc-e2e/src/support/e2e.ts b/apps/node-dist-vis-wc-e2e/src/support/e2e.ts
new file mode 100644
index 000000000..1c1a9e772
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/src/support/e2e.ts
@@ -0,0 +1,17 @@
+// ***********************************************************
+// This example support/e2e.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.ts using ES2015 syntax:
+import './commands';
diff --git a/apps/node-dist-vis-wc-e2e/tsconfig.json b/apps/node-dist-vis-wc-e2e/tsconfig.json
new file mode 100644
index 000000000..e28de1d79
--- /dev/null
+++ b/apps/node-dist-vis-wc-e2e/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "outDir": "../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["cypress", "node"],
+ "sourceMap": false,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["**/*.ts", "**/*.js", "cypress.config.ts", "**/*.cy.ts", "**/*.cy.js", "**/*.d.ts"]
+}
diff --git a/apps/node-dist-vis-wc/.eslintrc.json b/apps/node-dist-vis-wc/.eslintrc.json
new file mode 100644
index 000000000..b01d28e2b
--- /dev/null
+++ b/apps/node-dist-vis-wc/.eslintrc.json
@@ -0,0 +1,33 @@
+{
+ "extends": ["../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "hra",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "hra",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/node-dist-vis-wc/jest.config.ts b/apps/node-dist-vis-wc/jest.config.ts
new file mode 100644
index 000000000..19a203a78
--- /dev/null
+++ b/apps/node-dist-vis-wc/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'node-dist-vis-wc',
+ preset: '../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../coverage/apps/node-dist-vis-wc',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/node-dist-vis-wc/project.json b/apps/node-dist-vis-wc/project.json
new file mode 100644
index 000000000..9f6df8882
--- /dev/null
+++ b/apps/node-dist-vis-wc/project.json
@@ -0,0 +1,90 @@
+{
+ "name": "node-dist-vis-wc",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "hra",
+ "sourceRoot": "apps/node-dist-vis-wc/src",
+ "tags": ["type:app", "project:node-dist-vis"],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/node-dist-vis-wc",
+ "index": "apps/node-dist-vis-wc/src/index.html",
+ "browser": "apps/node-dist-vis-wc/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/node-dist-vis-wc/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "apps/node-dist-vis-wc/public"
+ }
+ ],
+ "styles": ["apps/node-dist-vis-wc/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "node-dist-vis-wc:build:production"
+ },
+ "development": {
+ "buildTarget": "node-dist-vis-wc:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "node-dist-vis-wc:build"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ },
+ "test": {
+ "executor": "@nx/jest:jest",
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+ "options": {
+ "jestConfig": "apps/node-dist-vis-wc/jest.config.ts"
+ }
+ },
+ "serve-static": {
+ "executor": "@nx/web:file-server",
+ "options": {
+ "buildTarget": "node-dist-vis-wc:build",
+ "port": 4200,
+ "staticFilePath": "dist/apps/node-dist-vis-wc/browser",
+ "spa": true
+ }
+ }
+ }
+}
diff --git a/apps/node-dist-vis-wc/public/favicon.ico b/apps/node-dist-vis-wc/public/favicon.ico
new file mode 100644
index 000000000..317ebcb23
Binary files /dev/null and b/apps/node-dist-vis-wc/public/favicon.ico differ
diff --git a/apps/node-dist-vis-wc/src/app/.gitkeep b/apps/node-dist-vis-wc/src/app/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/apps/node-dist-vis-wc/src/index.html b/apps/node-dist-vis-wc/src/index.html
new file mode 100644
index 000000000..a57b6318b
--- /dev/null
+++ b/apps/node-dist-vis-wc/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ node-dist-vis-wc
+
+
+
+
+
+
+
+
diff --git a/apps/node-dist-vis-wc/src/main.ts b/apps/node-dist-vis-wc/src/main.ts
new file mode 100644
index 000000000..ead2e58ef
--- /dev/null
+++ b/apps/node-dist-vis-wc/src/main.ts
@@ -0,0 +1 @@
+import '@hra-ui/node-dist-vis';
diff --git a/apps/node-dist-vis-wc/src/styles.scss b/apps/node-dist-vis-wc/src/styles.scss
new file mode 100644
index 000000000..90d4ee007
--- /dev/null
+++ b/apps/node-dist-vis-wc/src/styles.scss
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/apps/node-dist-vis-wc/src/test-setup.ts b/apps/node-dist-vis-wc/src/test-setup.ts
new file mode 100644
index 000000000..ab1eeeb33
--- /dev/null
+++ b/apps/node-dist-vis-wc/src/test-setup.ts
@@ -0,0 +1,8 @@
+// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
+globalThis.ngJest = {
+ testEnvironmentOptions: {
+ errorOnUnknownElements: true,
+ errorOnUnknownProperties: true,
+ },
+};
+import 'jest-preset-angular/setup-jest';
diff --git a/apps/node-dist-vis-wc/tsconfig.app.json b/apps/node-dist-vis-wc/tsconfig.app.json
new file mode 100644
index 000000000..fff4a41d4
--- /dev/null
+++ b/apps/node-dist-vis-wc/tsconfig.app.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"],
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/node-dist-vis-wc/tsconfig.editor.json b/apps/node-dist-vis-wc/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/node-dist-vis-wc/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/node-dist-vis-wc/tsconfig.json b/apps/node-dist-vis-wc/tsconfig.json
new file mode 100644
index 000000000..a28fec9ac
--- /dev/null
+++ b/apps/node-dist-vis-wc/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.spec.json"
+ }
+ ],
+ "extends": "../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/node-dist-vis-wc/tsconfig.spec.json b/apps/node-dist-vis-wc/tsconfig.spec.json
new file mode 100644
index 000000000..7870b7c01
--- /dev/null
+++ b/apps/node-dist-vis-wc/tsconfig.spec.json
@@ -0,0 +1,11 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "module": "commonjs",
+ "target": "es2016",
+ "types": ["jest", "node"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
+}
diff --git a/libs/design-system/package.json b/libs/design-system/package.json
index dcd7c9d93..9a904e643 100644
--- a/libs/design-system/package.json
+++ b/libs/design-system/package.json
@@ -29,7 +29,6 @@
"@angular/core": "18.2.1",
"@angular/material": "18.2.1",
"ngx-scrollbar": "^15.1.0",
- "ngx-color-picker": "^17.0.0",
"@angular/router": "18.2.1",
"@angular/cdk": "18.2.1"
},
diff --git a/libs/node-dist-vis/.eslintrc.json b/libs/node-dist-vis/.eslintrc.json
new file mode 100644
index 000000000..fc700f9b7
--- /dev/null
+++ b/libs/node-dist-vis/.eslintrc.json
@@ -0,0 +1,40 @@
+{
+ "extends": ["../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "hra",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "hra",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ },
+ {
+ "files": ["*.json"],
+ "parser": "jsonc-eslint-parser",
+ "rules": {
+ "@nx/dependency-checks": "error"
+ }
+ }
+ ]
+}
diff --git a/libs/node-dist-vis/README.md b/libs/node-dist-vis/README.md
new file mode 100644
index 000000000..4a0e4ed48
--- /dev/null
+++ b/libs/node-dist-vis/README.md
@@ -0,0 +1,7 @@
+# node-dist-vis
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test node-dist-vis` to execute the unit tests.
diff --git a/libs/node-dist-vis/jest.config.ts b/libs/node-dist-vis/jest.config.ts
new file mode 100644
index 000000000..118b6dae8
--- /dev/null
+++ b/libs/node-dist-vis/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'node-dist-vis',
+ preset: '../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../coverage/libs/node-dist-vis',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/libs/node-dist-vis/ng-package.json b/libs/node-dist-vis/ng-package.json
new file mode 100644
index 000000000..c201290e7
--- /dev/null
+++ b/libs/node-dist-vis/ng-package.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
+ "dest": "../../dist/libs/node-dist-vis",
+ "lib": {
+ "entryFile": "src/index.ts"
+ }
+}
diff --git a/libs/node-dist-vis/package.json b/libs/node-dist-vis/package.json
new file mode 100644
index 000000000..f6dcc7eee
--- /dev/null
+++ b/libs/node-dist-vis/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "@hra-ui/node-dist-vis",
+ "version": "0.0.1",
+ "peerDependencies": {
+ "@angular/core": "^18.2.0",
+ "@hra-ui/webcomponents": "0.0.1",
+ "papaparse": "^5.4.1",
+ "@hra-ui/utils": "0.0.1",
+ "rxjs": "7.8.0",
+ "@angular/common": "18.2.1",
+ "@deck.gl/carto": "~8.8.20",
+ "@deck.gl/core": "~8.8.20",
+ "@deck.gl/extensions": "~8.8.20",
+ "@deck.gl/layers": "~8.8.20",
+ "@vivjs/layers": "0.16.1"
+ },
+ "sideEffects": [
+ "index.ts"
+ ]
+}
diff --git a/libs/node-dist-vis/project.json b/libs/node-dist-vis/project.json
new file mode 100644
index 000000000..75ab26e40
--- /dev/null
+++ b/libs/node-dist-vis/project.json
@@ -0,0 +1,36 @@
+{
+ "name": "node-dist-vis",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/node-dist-vis/src",
+ "prefix": "hra",
+ "projectType": "library",
+ "tags": ["type:lib", "project:node-dist-vis", "webcomponent"],
+ "targets": {
+ "build": {
+ "executor": "@nx/angular:package",
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}"],
+ "options": {
+ "project": "libs/node-dist-vis/ng-package.json"
+ },
+ "configurations": {
+ "production": {
+ "tsConfig": "libs/node-dist-vis/tsconfig.lib.prod.json"
+ },
+ "development": {
+ "tsConfig": "libs/node-dist-vis/tsconfig.lib.json"
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "test": {
+ "executor": "@nx/jest:jest",
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+ "options": {
+ "jestConfig": "libs/node-dist-vis/jest.config.ts"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ }
+ }
+}
diff --git a/libs/node-dist-vis/src/index.ts b/libs/node-dist-vis/src/index.ts
new file mode 100644
index 000000000..0050f7e7f
--- /dev/null
+++ b/libs/node-dist-vis/src/index.ts
@@ -0,0 +1,11 @@
+import { createCustomElement } from '@hra-ui/webcomponents';
+import { NodeDistVisComponent } from './lib/node-dist-vis/node-dist-vis.component';
+
+export * from './lib/node-dist-vis/node-dist-vis.component';
+
+/** Custom element definition for CdeVisualizationComponent */
+export const CdeVisualizationElement = createCustomElement('hra-node-dist-vis', NodeDistVisComponent, {
+ providers: [],
+});
+
+export * from './lib/deck-gl-visualization/deck-gl-visualization.component';
diff --git a/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.html b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.html
new file mode 100644
index 000000000..c2e2ad0b6
--- /dev/null
+++ b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.html
@@ -0,0 +1 @@
+
diff --git a/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.scss b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.scss
new file mode 100644
index 000000000..5d4e87f30
--- /dev/null
+++ b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.scss
@@ -0,0 +1,3 @@
+:host {
+ display: block;
+}
diff --git a/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.spec.ts b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.spec.ts
new file mode 100644
index 000000000..009c40230
--- /dev/null
+++ b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { DeckGlVisualizationComponent } from './deck-gl-visualization.component';
+
+describe('DeckGlVisualizationComponent', () => {
+ let component: DeckGlVisualizationComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [DeckGlVisualizationComponent],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(DeckGlVisualizationComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.ts b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.ts
new file mode 100644
index 000000000..8afafb9b8
--- /dev/null
+++ b/libs/node-dist-vis/src/lib/deck-gl-visualization/deck-gl-visualization.component.ts
@@ -0,0 +1,265 @@
+import { CommonModule } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ effect,
+ ElementRef,
+ input,
+ output,
+ signal,
+ untracked,
+ viewChild,
+} from '@angular/core';
+import { colorCategories } from '@deck.gl/carto/typed';
+import { AccessorFunction, Color, COORDINATE_SYSTEM, Deck, DeckProps, OrbitView, Position } from '@deck.gl/core/typed';
+import { DataFilterExtension, DataFilterExtensionProps } from '@deck.gl/extensions/typed';
+import { LineLayer, PointCloudLayer } from '@deck.gl/layers/typed';
+import { ScaleBarLayer } from '@vivjs/layers';
+import { EdgeEntry, EdgeIndex } from '../models/edges';
+import { NodeEntry, NodeTargetKey } from '../models/nodes';
+
+type DeckCallbackParameters = Parameters>;
+
+const NO_HOVER = Symbol();
+const ORIGIN: Position = [0, 0, 0];
+const COLOR_WHITE: Color = [255, 255, 255];
+const SELECTION_RANGE: [number, number] = [0, 10];
+const SELECTION_VALUE_INSIDE_RANGE = 5;
+const SELECTION_VALUE_OUT_OF_RANGE = 100;
+
+/** DeckGl Visualization Component */
+@Component({
+ selector: 'hra-deck-gl-visualization',
+ standalone: true,
+ imports: [CommonModule],
+ templateUrl: './deck-gl-visualization.component.html',
+ styleUrl: './deck-gl-visualization.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DeckGlVisualizationComponent {
+ /** Nodes for the visualization */
+ readonly nodes = input.required();
+ /** Edges for the visualization */
+ readonly edges = input.required();
+ /** Selection for the visualization */
+ readonly selection = input.required();
+ /** Colormap for the visualization */
+ readonly colorMap = input.required<{ domain: string[]; range: Color[] }>();
+ /** Node target key for the visualization */
+ readonly nodeTargetKey = input.required();
+
+ /** Event for click on the node */
+ readonly nodeClick = output();
+ /** Event for hover on the node */
+ readonly nodeHover = output();
+
+ /** Reference to the canvas element */
+ private readonly canvas = viewChild.required>('canvas');
+ /** Configuration of the view state of the deck gl */
+ private readonly viewState = signal