diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1c4b2bb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# ---> VisualStudioCode +/uploaded-files/ diff --git a/backend/package-lock.json b/backend/package-lock.json index 1fe7e40c..179658b9 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -19,6 +19,7 @@ "form-data": "^4.0.0", "formidable": "^1.2.1", "node-opcua": "^2.62.5", + "reflect-metadata": "0.1.13", "request": "^2.88.0", "rimraf": "3.0.2", "rxjs": "^7.4.0", @@ -12911,8 +12912,7 @@ "node_modules/reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "peer": true + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "node_modules/regexp.prototype.flags": { "version": "1.3.1", @@ -25132,8 +25132,7 @@ "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "peer": true + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "regexp.prototype.flags": { "version": "1.3.1", diff --git a/backend/package.json b/backend/package.json index cfeced6d..c2534282 100644 --- a/backend/package.json +++ b/backend/package.json @@ -25,6 +25,7 @@ "formidable": "^1.2.1", "node-opcua": "^2.62.5", "request": "^2.88.0", + "reflect-metadata": "0.1.13", "rimraf": "3.0.2", "rxjs": "^7.4.0", "sparql-result-converter": "^3.0.1", diff --git a/backend/src/routes/capabilities/capability.service.ts b/backend/src/routes/capabilities/capability.service.ts index d10de521..12203b94 100644 --- a/backend/src/routes/capabilities/capability.service.ts +++ b/backend/src/routes/capabilities/capability.service.ts @@ -199,6 +199,7 @@ export class CapabilityService { } }`); const capabilities = converter.convertToDefinition(queryResult.results.bindings, capabilityMapping).getFirstRootElement() as CapabilityDto[]; + return capabilities; } catch (error) { console.error(`Error while returning capabilities of skill ${skillIri}, ${error}`); diff --git a/backend/src/routes/production-modules/module.service.ts b/backend/src/routes/production-modules/module.service.ts index 2935dc10..d4aae3a3 100644 --- a/backend/src/routes/production-modules/module.service.ts +++ b/backend/src/routes/production-modules/module.service.ts @@ -50,7 +50,6 @@ export class ModuleService { const moduleSkillDtos = await this.skillService.getSkillsOfModule(moduleDto.iri); moduleDto.skillDtos = moduleSkillDtos; } - return productionModuleDtos; } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7e2148ce..50ae2e93 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,6 +26,7 @@ "chartjs-plugin-annotation": "^1.4.0", "chartjs-plugin-datalabels": "^2.0.0", "core-js": "2.6.5", + "d3": "^7.4.0", "formidable": "^2.0.1", "ng2-charts": "3.0.11", "rxjs": "^7.4.0", @@ -37,6 +38,7 @@ "@angular/cli": "13.3.5", "@angular/compiler-cli": "13.3.8", "@angular/language-service": "13.3.8", + "@types/d3": "^7.4.0", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "2.0.5", "@typescript-eslint/eslint-plugin": "^2.23.0", @@ -3380,6 +3382,259 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", "dev": true }, + "node_modules/@types/d3": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", + "integrity": "sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", + "dev": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", + "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", + "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==", + "dev": true + }, + "node_modules/@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", + "dev": true + }, + "node_modules/@types/d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", + "dev": true + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==", + "dev": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", + "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", + "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==", + "dev": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", + "dev": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", + "dev": true, + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", + "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==", + "dev": true + }, + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "dev": true + }, + "node_modules/@types/d3-geo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", + "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz", + "integrity": "sha512-g+sey7qrCa3UbsQlMZZBOHROkFqx7KZKvUpRzI/tAp/8erZWpYq7FgNKvYwebi2LaEiVs1klhUfd3WCThxmmWQ==", + "dev": true + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "dev": true, + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", + "dev": true + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", + "dev": true + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", + "dev": true + }, + "node_modules/@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", + "dev": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "dev": true, + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", + "dev": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.3.tgz", + "integrity": "sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA==", + "dev": true + }, + "node_modules/@types/d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==", + "dev": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "dev": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", + "dev": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", + "dev": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.2.tgz", + "integrity": "sha512-jo5o/Rf+/u6uerJ/963Dc39NI16FQzqwOc54bwvksGAdVfvDrqDpVeq95bEvPtBwLCVZutAEyAtmSyEMxN7vxQ==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", + "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", + "dev": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/eslint": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", @@ -3435,6 +3690,12 @@ "@types/range-parser": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", + "dev": true + }, "node_modules/@types/http-proxy": { "version": "1.17.9", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", @@ -5924,15 +6185,404 @@ "cssesc": "bin/cssesc" }, "engines": { - "node": ">=4" + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "node_modules/d3": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", + "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", + "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", + "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", + "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", - "dev": true - }, "node_modules/damerau-levenshtein": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", @@ -6145,6 +6795,14 @@ "node": ">=8" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -8867,6 +9525,14 @@ "node": ">=8" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/ip": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", @@ -13588,6 +14254,11 @@ "rimraf": "bin.js" } }, + "node_modules/robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -13620,6 +14291,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "node_modules/rxjs": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz", @@ -13641,8 +14317,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { "version": "1.49.9", @@ -18402,6 +19077,259 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", "dev": true }, + "@types/d3": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", + "integrity": "sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==", + "dev": true, + "requires": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", + "dev": true + }, + "@types/d3-axis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", + "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-brush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", + "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==", + "dev": true + }, + "@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", + "dev": true + }, + "@types/d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", + "dev": true, + "requires": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", + "dev": true + }, + "@types/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==", + "dev": true + }, + "@types/d3-drag": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", + "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-dsv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", + "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==", + "dev": true + }, + "@types/d3-ease": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", + "dev": true + }, + "@types/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", + "dev": true, + "requires": { + "@types/d3-dsv": "*" + } + }, + "@types/d3-force": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", + "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==", + "dev": true + }, + "@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "dev": true + }, + "@types/d3-geo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", + "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", + "dev": true, + "requires": { + "@types/geojson": "*" + } + }, + "@types/d3-hierarchy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz", + "integrity": "sha512-g+sey7qrCa3UbsQlMZZBOHROkFqx7KZKvUpRzI/tAp/8erZWpYq7FgNKvYwebi2LaEiVs1klhUfd3WCThxmmWQ==", + "dev": true + }, + "@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "dev": true, + "requires": { + "@types/d3-color": "*" + } + }, + "@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", + "dev": true + }, + "@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", + "dev": true + }, + "@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", + "dev": true + }, + "@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", + "dev": true + }, + "@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "dev": true, + "requires": { + "@types/d3-time": "*" + } + }, + "@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", + "dev": true + }, + "@types/d3-selection": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.3.tgz", + "integrity": "sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA==", + "dev": true + }, + "@types/d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==", + "dev": true, + "requires": { + "@types/d3-path": "*" + } + }, + "@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "dev": true + }, + "@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", + "dev": true + }, + "@types/d3-timer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", + "dev": true + }, + "@types/d3-transition": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.2.tgz", + "integrity": "sha512-jo5o/Rf+/u6uerJ/963Dc39NI16FQzqwOc54bwvksGAdVfvDrqDpVeq95bEvPtBwLCVZutAEyAtmSyEMxN7vxQ==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-zoom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", + "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", + "dev": true, + "requires": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "@types/eslint": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", @@ -18457,6 +19385,12 @@ "@types/range-parser": "*" } }, + "@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", + "dev": true + }, "@types/http-proxy": { "version": "1.17.9", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", @@ -20391,6 +21325,284 @@ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", "dev": true }, + "d3": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", + "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + } + }, + "d3-array": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", + "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + } + }, + "d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-contour": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", + "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", + "requires": { + "d3-array": "^3.2.0" + } + }, + "d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "requires": { + "delaunator": "5" + } + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "requires": { + "d3-dsv": "1 - 3" + } + }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-geo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", + "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", + "requires": { + "d3-array": "2.5.0 - 3" + } + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" + }, + "d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" + }, + "d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, + "d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, "damerau-levenshtein": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", @@ -20551,6 +21763,14 @@ } } }, + "delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "requires": { + "robust-predicates": "^3.0.0" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -22545,6 +23765,11 @@ } } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "ip": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", @@ -26077,6 +27302,11 @@ "glob": "^7.1.3" } }, + "robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -26092,6 +27322,11 @@ "queue-microtask": "^1.2.2" } }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "rxjs": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz", @@ -26115,8 +27350,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { "version": "1.49.9", diff --git a/frontend/package.json b/frontend/package.json index 5a39f6d0..9cfe533b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,6 +31,7 @@ "chartjs-plugin-annotation": "^1.4.0", "chartjs-plugin-datalabels": "^2.0.0", "core-js": "2.6.5", + "d3": "^7.4.0", "formidable": "^2.0.1", "ng2-charts": "3.0.11", "rxjs": "^7.4.0", @@ -42,6 +43,7 @@ "@angular/cli": "13.3.5", "@angular/compiler-cli": "13.3.8", "@angular/language-service": "13.3.8", + "@types/d3": "^7.4.0", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "2.0.5", "@typescript-eslint/eslint-plugin": "^2.23.0", diff --git a/frontend/src/layout/components/sidebar/sidebar.component.html b/frontend/src/layout/components/sidebar/sidebar.component.html index 5dea069b..57a49972 100644 --- a/frontend/src/layout/components/sidebar/sidebar.component.html +++ b/frontend/src/layout/components/sidebar/sidebar.component.html @@ -46,6 +46,11 @@ + +   + Graph-Visualization +   SkillMeX Configuration diff --git a/frontend/src/layout/layout-routing.module.ts b/frontend/src/layout/layout-routing.module.ts index 6e8853c0..3efcbe27 100644 --- a/frontend/src/layout/layout-routing.module.ts +++ b/frontend/src/layout/layout-routing.module.ts @@ -14,6 +14,7 @@ const routes: Routes = [ { path: 'capabilities', loadChildren: () => import('../modules/capabilities/capability.module').then(m => m.CapabilityModule)}, { path: 'production-processes', loadChildren: () => import('../modules/production-processes/production-processes.module').then(m => m.ProductionProcessesModule)}, { path: 'skillmex-configuration', loadChildren: () => import('../modules/skillmex-configuration/skillmex-configuration.module').then(m => m.SkillMexConfigurationModule)}, + { path: 'graph-visualization', loadChildren: () => import('../modules/graph-visualization/graph-visualization.module').then(m =>m.GraphVisualizationModule)}, { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)}, { path: 'charts', loadChildren: () => import('./charts/charts.module').then(m => m.ChartsModule)}, { path: 'blank-page', loadChildren: () => import('./blank-page/blank-page.module').then(m => m.BlankPageModule)}, diff --git a/frontend/src/modules/capabilities/capability-registration/capability-registration.component.ts b/frontend/src/modules/capabilities/capability-registration/capability-registration.component.ts index bf85b38c..699881da 100644 --- a/frontend/src/modules/capabilities/capability-registration/capability-registration.component.ts +++ b/frontend/src/modules/capabilities/capability-registration/capability-registration.component.ts @@ -1,15 +1,15 @@ import { Component, OnInit } from '@angular/core'; @Component({ - selector: 'app-capability-registration', - templateUrl: './capability-registration.component.html', - styleUrls: ['./capability-registration.component.scss'] + selector: 'app-capability-registration', + templateUrl: './capability-registration.component.html', + styleUrls: ['./capability-registration.component.scss'] }) export class CapabilityRegistrationComponent implements OnInit { - constructor() { } + constructor() { } - ngOnInit() { - } + ngOnInit() { + } } diff --git a/frontend/src/modules/graph-visualization/D3GraphData.ts b/frontend/src/modules/graph-visualization/D3GraphData.ts new file mode 100644 index 00000000..b339b820 --- /dev/null +++ b/frontend/src/modules/graph-visualization/D3GraphData.ts @@ -0,0 +1,109 @@ + +import * as d3Force from 'd3-force'; + +export enum NodeType { + None = "None", + Module ="D3ModuleNode", + Skill = "D3SkillNode", + Capability = "D3CapabilityNode", + Input = "D3InputNode", + Output = "D3OutputNode" +} + +export class D3Node implements d3Force.SimulationNodeDatum { + index?: number | undefined; + x?: number | undefined; + y?: number | undefined; + vx?: number | undefined; + vy?: number | undefined; + fx?: number | null | undefined; + fy?: number | null | undefined; + + constructor( + public id: string, + public name: string, + public type: NodeType = NodeType.None, + x?, y?) { + this.x = x; + this.y = y; + } +} + +export class D3ModuleNode extends D3Node { + constructor(id: string, name: string) { + super(id, name, NodeType.Module); + } +} +export class D3SkillNode extends D3Node{ + constructor(id: string, name: string) { + super(id, name, NodeType.Skill); + } +} + +export class D3CapabilityNode extends D3Node{ + constructor(id: string, name: string) { + super(id, name, NodeType.Capability); + } +} + +export class D3InputNode extends D3Node{ + constructor(id: string, name: string) { + super(id, name, NodeType.Input); + } +} + +export class D3OutputNode extends D3Node{ + constructor(id: string, name: string) { + super(id, name, NodeType.Output); + } +} + +export class D3Link implements d3Force.SimulationLinkDatum { + constructor( + public source: D3Node, + public target: D3Node, + public type: string) { } +} + + +export class D3GraphData { + constructor(private nodes: D3Node[] = [], private links: D3Link[] = []) { } + + addNode(node: D3Node): void { + this.nodes.push(node); + } + + addLink(link: D3Link): void { + this.links.push(link); + } + + getNodes(): D3Node[] {return this.nodes;} + getLinks(): D3Link[] {return this.links;} + + getNodesById(id: string): D3Node[] { + return this.nodes.filter(node => node.id == id); + } + + getNodesByNodeTyp(type: string): D3Node[] { + return this.nodes.filter(node => node.type === type); + } + + + // Adds another D3GraphData object to the current one + appendAndConnectData(data: D3GraphData, idToConnectTo: string, nodeType: NodeType, connectionType: string): void { + const newNodes = data.getNodes(); + const newLinks = data.getLinks(); + // Add the new data + newNodes.forEach(newNode => this.addNode(newNode)); + newLinks.forEach(newLink => this.addLink(newLink)); + // Connect with existing nodes + const oldNodesToConnect = this.getNodesById(idToConnectTo); + const newNodesToConnect = this.getNodesByNodeTyp(nodeType); + + oldNodesToConnect.forEach(oldNode => { + newNodesToConnect.forEach(newNode => { + this.addLink(new D3Link(oldNode, newNode, connectionType)); + }); + }); + } +} diff --git a/frontend/src/modules/graph-visualization/graph-visualization.component.html b/frontend/src/modules/graph-visualization/graph-visualization.component.html new file mode 100644 index 00000000..ff8bcf04 --- /dev/null +++ b/frontend/src/modules/graph-visualization/graph-visualization.component.html @@ -0,0 +1,7 @@ +

+Graph-Visualization +

+
+ + +
diff --git a/frontend/src/modules/graph-visualization/graph-visualization.component.scss b/frontend/src/modules/graph-visualization/graph-visualization.component.scss new file mode 100644 index 00000000..38ecf2c6 --- /dev/null +++ b/frontend/src/modules/graph-visualization/graph-visualization.component.scss @@ -0,0 +1,8 @@ +.svgContainer { + height: 600px; + border: 1px solid #bbb; + border-radius: 5px; + width: 100%; + overflow: hidden; + display: block; +} diff --git a/frontend/src/modules/graph-visualization/graph-visualization.component.ts b/frontend/src/modules/graph-visualization/graph-visualization.component.ts new file mode 100644 index 00000000..175d3cdb --- /dev/null +++ b/frontend/src/modules/graph-visualization/graph-visualization.component.ts @@ -0,0 +1,344 @@ +import { Component, ViewEncapsulation, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; +import * as d3Selection from 'd3-selection'; +import * as d3Force from 'd3-force'; +import * as d3Transition from 'd3-transition'; +import * as d3Scale from 'd3-scale'; +import * as d3ScaleChromatic from'd3-scale-chromatic'; +import * as d3Drag from'd3-drag'; +import { ActivatedRoute } from '@angular/router'; +import { NodeCreatorService } from './node-creator.service'; +import { D3Link, D3Node, NodeType } from './D3GraphData'; +import {v4} from "uuid"; + + +@Component({ + selector: 'graph-visualization', + encapsulation: ViewEncapsulation.None, + templateUrl: './graph-visualization.component.html', + styleUrls: ['./graph-visualization.component.scss'] +}) +export class GraphVisualizationComponent implements AfterViewInit { + + name: string; + svg: d3Selection.Selection; // Reference to the svg element of the simulation + + nodesContainer: any; // Container for all nodes + nodes: d3Selection.Selection; // The nodes of the simulation + texts: any; // The node texts of the simulation + + linksContainer: any; // Container for all links + links: d3Selection.Selection; ; // The links of the simulation + linkTexts: any; // The linkTexts of the simulation + + /** Loaded data: Connected modules with their capabilities and skills*/ + data: { + links: D3Link[]; + nodes: D3Node[]; + }; + + color: any; // Contains scale of colors + + typeColors = new Map(); // Used to store colors per type + /**Simulation of the force directed graph */ + simulation: d3Force.Simulation; + + + // margin = { top: 10, right: 30, bottom: 30, left: 40 }; + margin = 5; + width = 100; + height = 100; + + + nodeRadius = 16; // standard radius of a node + + constructor( + private route: ActivatedRoute, + private nodeCreatorService: NodeCreatorService + ) {} + + @ViewChild('g') svgContainer: ElementRef; + svgHeight = 100; + svgWidth = 200; + moduleName: string; + + ngAfterViewInit(): void { + this.svgWidth = this.svgContainer.nativeElement.offsetWidth; + this.svgHeight = this.svgContainer.nativeElement.offsetHeight; + console.log(this.svgWidth); + console.log(this.svgHeight); + this.route.params.subscribe(p => { + this.moduleName = p['moduleName']; + }); + // this.data = this.nodeCreatorService.getAllNodes(this.moduleName); // load data created by node-creator.service + this.nodeCreatorService.getAllNodes().subscribe(data => { + this.data = data; + this.setSvg(); + this.setSimulation(); + }); + } + + /**Defines settings of the SVG and the color-scheme of the nodes */ + setSvg(): void { + this.svg = d3Selection.select("#graph") + .attr("width",this.svgWidth + 65) + .attr("height", this.svgHeight + 65); + // this.svg = d3Selection.select("#graph") // size definitions for the svg + + this.color = d3Scale.scaleOrdinal(d3ScaleChromatic.schemeCategory10); // chooses a scheme category for node colours + + const markerBoxWidth = 10; + const markerBoxHeight = 8; + this.svg.append('defs').append('marker') // marker/ arrow settings + .attr("id", 'arrowhead') + .attr('viewBox', [0, -4, markerBoxWidth, markerBoxHeight]) //coordinate system + .attr('refX', 2*markerBoxWidth) // arrow position and dimensions + .attr('refY', 0) + .attr('orient', 'auto') + .attr('markerWidth', 1.5*markerBoxWidth) + .attr('markerHeight', 1.5*markerBoxHeight) + .attr('xoverflow', 'visible') + .append('path') + .attr('d', 'M 0,-4 L 10,0 L 0,4') + .attr('fill', '#555') + .style('stroke', 'none'); + + // Define elemennt containers. Important nodes after links so that nodes are rendered on top + this.linksContainer = this.svg.append('g').attr('class', 'linksContainer'); + this.nodesContainer = this.svg.append('g').attr('class', 'nodesContainer'); + } + + /**Defines settings of the simulation */ + setSimulation(): void { + this.simulation = d3Force.forceSimulation(this.data.nodes) + .force("link", d3Force.forceLink() + .id((node: D3Node) => node.id) + .distance(150) + .links(this.data.links)) + .force("collision", d3Force.forceCollide(this.nodeRadius*1.5)) + .force("charge", d3Force.forceManyBody().strength(-300)) // node magnetism / attraction + .force("center", d3Force.forceCenter(this.svgWidth/ 2, this.svgHeight / 2)) //Zentrierung der Nodes + .on("tick", this.ticked); // tick on every step of the simulation + + this.updateSimulation(); + } + + + + /** + * Draws the graph, executed first on AfterContentInit while setSimulation() and on every doubleclick on a node + */ + updateSimulation(): void { + this.nodes = this.nodesContainer.selectAll(".nodes") + .data(this.data.nodes, (d) => this.convertSpecialChars(d.id)); + + const nodeEnter= this.nodes.enter().append("circle") + .attr("class", "nodes") + .attr("id", (d) => this.convertSpecialChars(d.id)) + .attr("r", (d) => this.nodeRadius) + .attr("cx", (d) => { return d.x; }) + .attr("cy", (d) => { return d.y; }); + + nodeEnter.on('mouseover', this.mouseover); + nodeEnter.on('mouseout', this.mouseout); + nodeEnter.style("fill", this.setNodeStyle); + nodeEnter.on('dblclick', this.nodeDoubleClick); + nodeEnter.call(d3Drag.drag() // reactions when dragging a node + .on("start", this.dragstarted) + .on("drag", this.dragged) + .on("end", this.dragended)); + this.nodes = this.nodes.merge(nodeEnter); // merge old elements with entered elements + + this.nodes.exit().remove(); // remove data-elements of exit-selection(all old elements, wich are not in the new dataset) + + this.links = this.linksContainer.selectAll(".links").data(this.data.links); + + const linkEnter=this.links.enter() + .append("line") + .style("stroke", "#555") + .attr("class", "links") + .attr("x2", (d) => { return d.source.x; }) + .attr("y2", (d) => { return d.source.y; }) + .attr("x1", (d) => { return d.target.x; }) + .attr("x1", (d) => { return d.target.y; }) + .attr('marker-end', 'url(#arrowhead)') // arrow on end of the link + ; + + this.links = this.links.merge(linkEnter); // merge old elements with entered elements + this.links.exit().remove(); // remove data-elements of exit-selection(all old elements, wich are not in the new dataset) + + this.linkTexts = this.linksContainer.selectAll('.linkTexts') + .data(this.data.links); + + const linkTextsEnter = this.linkTexts.enter().append('text') + .attr("class", "linkTexts") + // .data(this.data.links, function (l: D3Link){return `${l.source.id}_${l.target.id}`;}) + .attr("font-weight", "normal") + .text((d) => d.type); // get text from data + + this.linkTexts = this.linkTexts.merge(linkTextsEnter); + this.linkTexts.exit().remove(); + + this.texts = this.nodesContainer.selectAll(".nodeTexts").data(this.data.nodes); + const textEnter=this.texts.enter().append("text") + .attr("class", "nodeTexts") + .data(this.data.nodes, function (d){return d.id;}) + .attr("font-weight", "normal") + .text((d) => d.name); // get text from data + + this.texts=this.texts.merge(textEnter); + this.texts.exit().remove(); + + + + this.simulation.nodes(this.data.nodes); + } + + /** + * Function executed on every tick in the simulation. Defines restrictions for positions of node, text, link-text and link. The functions computes the position of each element + * @param d The position of every graph element (i.e. node, link...) + */ + ticked = (): void => { + this.nodes + .attr("cx", (d: D3Node) => { + d.x = Math.max(0 + this.nodeRadius, Math.min(d.x, this.svgWidth - 5 * this.nodeRadius)); + const relativeDragX = 100 * d.x / this.svgWidth; + return relativeDragX + '%'; + }) + .attr("cy", (d: D3Node) => { + d.y = Math.max(0 + this.nodeRadius, Math.min(d.y, this.svgHeight - 5 * this.nodeRadius)); + const relativeDragY = 100 * d.y / this.svgHeight; + return relativeDragY + '%'; + }); + + this.links + .attr("x1", (l: D3Link) => { // restrictions for link positions in the svg + l.source.x = Math.max(0 + this.nodeRadius, Math.min(l.source.x, this.svgWidth - 5 * this.nodeRadius)); + const relativeSourceX = 100 * l.source.x / this.svgWidth; + return relativeSourceX + '%'; + }) + .attr("y1", (l: D3Link) => { + l.source.y = Math.max(0 + this.nodeRadius, Math.min(l.source.y, this.svgHeight - 5 * this.nodeRadius)); + const relativeSourceY = 100 * l.source.y / this.svgHeight; + return relativeSourceY + '%'; + }) + .attr("x2", (l: D3Link) => { + l.target.x = Math.max(0 + this.nodeRadius, Math.min(l.target.x, this.svgWidth - 5 * this.nodeRadius)); + const relativeTargetX = 100 * l.target.x / this.svgWidth; + return relativeTargetX + '%'; + }) + .attr("y2", (l: D3Link) => { + l.target.y = Math.max(0 + this.nodeRadius, Math.min(l.target.y, this.svgHeight - 5 * this.nodeRadius)); + const relativeTargetY = 100 * l.target.y / this.svgHeight; + return relativeTargetY + '%'; + }); + + this.texts + .attr("dx", (d: D3Node) => { // restrictions for node text positions in the svg + const relativeRadius = 100 * this.nodeRadius / this.svgWidth; + const relativeDragX = 100 * d.x / this.svgWidth; + return (relativeDragX + relativeRadius) + '%'; + }) + .attr("dy", (d: D3Node) => { + const relativeRadius = 100 * this.nodeRadius / this.svgHeight; + const relativeDragY = 100 * d.y / this.svgHeight; + return (relativeDragY - 0.5*relativeRadius) + '%'; + }); + + this.linkTexts + .attr("dx", (l: D3Link) => { // restrictions for link text positions in the svg + const midX = (l.target.x + l.source.x) / 2 - 10; + const relativeMidX = 100 * midX / this.svgWidth; + return relativeMidX + "%"; + }) + .attr("dy", (l: D3Link) => { + const midY = (l.target.y + l.source.y) / 2; + const relativeMidY = 100 * midY / this.svgHeight; + return relativeMidY + "%"; + }); + + } + + private convertSpecialChars(iri: string): string { + return iri.replace(/([://#.])+/g,"_"); + } + + /** + * Function executed on a drag start + */ + dragstarted = (event: d3Drag.D3DragEvent, d: d3Force.SimulationNodeDatum): void => { + if (!d3Transition.active(d as d3Selection.BaseType)) this.simulation.alphaTarget(0.3).restart(); + d.fx = event.x; + d.fy = event.y; + } + + /** + * Drag function, executed on every drag movement + * @param d The dragged node + */ + dragged(event: d3Drag.D3DragEvent, d: d3Force.SimulationNodeDatum): void { + d.fx = event.x; + d.fy = event.y; + } + + dragended= (event: d3Drag.D3DragEvent, d: d3Force.SimulationNodeDatum): void => { + if (!d3Transition.active(d as d3Selection.BaseType)) this.simulation.alphaTarget(.03); + d.fx = null; + d.fy = null; + } + + /** + * Mouseover function, executed when mouse over node. The radius of the node will increase. + * @param d node under the cursor + */ + mouseover = (event: MouseEvent, d: D3Node): void => { + this.increaseNodeRadius(d); + } + + private increaseNodeRadius(d: D3Node): void { + const elementId = `#${this.convertSpecialChars(d.id)}`; + this.nodesContainer.select(elementId).transition() + .duration(200) + .attr('r', this.nodeRadius * 1.5); + } + + /** + * Mousout function, executed when mouse cursor leaves the node. Decreases radius to origin. + * @param d node wich is left by the cursor after mouseover + */ + mouseout = (event: MouseEvent, d: D3Node): void => { + this.decreaseNodeRadius(d); + } + + private decreaseNodeRadius(d: D3Node): void { + const elementId = `#${this.convertSpecialChars(d.id)}`; + this.nodesContainer.select(elementId).transition() + .duration(200) + .attr('r', this.nodeRadius); + } + + + /** + * Doubleclick function, executed on every doubleclick on a node + *@param d The clicked node + */ + nodeDoubleClick = (e: MouseEvent, d: D3Node)=> { + const nodeId: string = "a" + v4(); + const testNode = new D3Node(nodeId , nodeId.substring(0,4), NodeType.Skill); + const testLink = new D3Link(d, testNode, "test"); + this.data.links.push(testLink); + this.data.nodes.push(testNode); + this.updateSimulation(); + } + + /** Returns the color of the inner circle of a node */ + setNodeStyle = (d: D3Node) => { + const typeColor = this.typeColors.get(d.type); + if(!typeColor) { + const newTypeColor = this.color(Math.random() * 10); + this.typeColors.set(d.type, newTypeColor); + } + + return this.typeColors.get(d.type); + } + +} diff --git a/frontend/src/modules/graph-visualization/graph-visualization.module.ts b/frontend/src/modules/graph-visualization/graph-visualization.module.ts new file mode 100644 index 00000000..abbf5da3 --- /dev/null +++ b/frontend/src/modules/graph-visualization/graph-visualization.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { GraphVisualizationComponent } from './graph-visualization.component'; +import {GraphVisualizationRouter} from './graph-visualization.routing'; +import { ModuleService } from '../../shared/services/module.service'; +import { NodeCreatorService } from './node-creator.service'; + +@NgModule({ + imports: [ + GraphVisualizationRouter, + ], + declarations: [ + GraphVisualizationComponent + ], + providers: [ + ModuleService, + NodeCreatorService + + ] +}) +export class GraphVisualizationModule { } diff --git a/frontend/src/modules/graph-visualization/graph-visualization.routing.ts b/frontend/src/modules/graph-visualization/graph-visualization.routing.ts new file mode 100644 index 00000000..ba430b6c --- /dev/null +++ b/frontend/src/modules/graph-visualization/graph-visualization.routing.ts @@ -0,0 +1,20 @@ +import { Routes, RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import {GraphVisualizationComponent} from './graph-visualization.component'; + +const routes: Routes = [ + { path: 'modules/:moduleName', + component: GraphVisualizationComponent, + + }, + {path:'modules', component: GraphVisualizationComponent + + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class GraphVisualizationRouter {} diff --git a/frontend/src/modules/graph-visualization/node-creator.service.spec.ts b/frontend/src/modules/graph-visualization/node-creator.service.spec.ts new file mode 100644 index 00000000..2ba009ab --- /dev/null +++ b/frontend/src/modules/graph-visualization/node-creator.service.spec.ts @@ -0,0 +1,16 @@ +/* tslint:disable:no-unused-variable */ + +import { TestBed, async, inject } from '@angular/core/testing'; +import { NodeCreatorService } from './node-creator.service'; + +describe('Service: NodeCreator', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [NodeCreatorService] + }); + }); + + it('should ...', inject([NodeCreatorService], (service: NodeCreatorService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/frontend/src/modules/graph-visualization/node-creator.service.ts b/frontend/src/modules/graph-visualization/node-creator.service.ts new file mode 100644 index 00000000..768d2037 --- /dev/null +++ b/frontend/src/modules/graph-visualization/node-creator.service.ts @@ -0,0 +1,75 @@ +import { Injectable } from '@angular/core'; +import { map, Observable } from 'rxjs'; +import { ModuleService } from '../../shared/services/module.service'; +import { D3CapabilityNode, D3InputNode, D3Link, D3ModuleNode, D3Node, D3OutputNode, D3SkillNode, NodeType } from './D3GraphData'; + +@Injectable({ + providedIn: 'root' +}) +export class NodeCreatorService { + apiRoot = "/api"; + + constructor( + private moduleService: ModuleService + ) {} + + getAllNodes(): Observable<{links: D3Link[]; nodes: D3Node[] }> { + console.log("getting all nodes"); + + // const receivedData = await (lastValueFrom(this.moduleService.getAllModules())); + const $receivedData$ = this.moduleService.getAllModules(); + + const nodeData= {nodes:[], links:[]}; + const id=0; // ID start value + return $receivedData$.pipe(map(data => { + data.forEach(receivedModule => { //loop over all modules + const moduleNode = new D3ModuleNode(receivedModule.iri, receivedModule.getLocalName()); + nodeData.nodes.push(moduleNode); + + receivedModule.capabilities.forEach(capability=>{ //loop over all capabilities of current module + const capNode = new D3CapabilityNode(capability.iri, capability.getLocalName()); + nodeData.nodes.push(capNode); + nodeData.links.push(new D3Link(moduleNode, capNode, "hasCapability")); + + capability.inputs.forEach(input=>{ + const inputNode = new D3InputNode(input.iri, input.getLocalName()); + nodeData.nodes.push(inputNode); + nodeData.links.push(new D3Link(capNode, inputNode, "hasInput")); + + const inputTypeNode = new D3Node(input.type, input.type, NodeType.None); + nodeData.nodes.push(inputTypeNode); + nodeData.links.push(new D3Link(inputNode, inputTypeNode, "rdf:type")); + }); + + capability.outputs.forEach(output=>{ + const outputNode = new D3OutputNode(output.iri, output.getLocalName()); + nodeData.nodes.push(outputNode); + nodeData.links.push(new D3Link(capNode, outputNode, "hasInput")); + + const outputTypeNode = new D3Node(output.type, output.type, NodeType.None); + nodeData.nodes.push(outputTypeNode); + nodeData.links.push(new D3Link(outputNode, outputTypeNode, "rdf:type")); + }); + + capability.skills.forEach(skill=>{ + const skillNode = new D3SkillNode(skill.iri, skill.getLocalName()); + nodeData.nodes.push(skillNode); + nodeData.links.push(new D3Link(capNode, skillNode, "executable_via_Skill")); + }); + + }); + + }); + + return nodeData; + })); + } + + +} + + + + + + diff --git a/frontend/src/modules/production-modules/module-overview/module-overview.component.html b/frontend/src/modules/production-modules/module-overview/module-overview.component.html index ac9a8893..0b2c4250 100644 --- a/frontend/src/modules/production-modules/module-overview/module-overview.component.html +++ b/frontend/src/modules/production-modules/module-overview/module-overview.component.html @@ -3,6 +3,9 @@

{{module.getLocalName()}}

+
+ +
diff --git a/frontend/src/modules/production-modules/module-registration/module-registration.component.ts b/frontend/src/modules/production-modules/module-registration/module-registration.component.ts index 161409eb..56563c91 100644 --- a/frontend/src/modules/production-modules/module-registration/module-registration.component.ts +++ b/frontend/src/modules/production-modules/module-registration/module-registration.component.ts @@ -6,24 +6,9 @@ import { HttpClient } from "@angular/common/http"; selector: 'app-module-registration', templateUrl: './module-registration.component.html', styleUrls: ['./module-registration.component.scss'] - + }) export class ModuleRegistrationComponent { - constructor(private httpClient: HttpClient, - private moduleService: ModuleService,) { } - - ontologyString="Enter Ontology here"; - errMessage: any; - saveOntology() { - console.log(this.ontologyString); - this.moduleService.addModule(this.ontologyString).subscribe(null, - (err) => this.errMessage = err.error.message, - () => { - this.errMessage = ""; - this.ontologyString="Ontology registered"; //Variablenwert wird nicht in ontologyString gespeichert - } - ); - - } -} \ No newline at end of file + constructor() { } +} diff --git a/frontend/src/modules/production-modules/production-module.component.html b/frontend/src/modules/production-modules/production-module.component.html index 09c0fc29..7e169aa6 100644 --- a/frontend/src/modules/production-modules/production-module.component.html +++ b/frontend/src/modules/production-modules/production-module.component.html @@ -2,13 +2,13 @@

Production Modules

diff --git a/frontend/src/modules/production-modules/production-module.routing.ts b/frontend/src/modules/production-modules/production-module.routing.ts index 3e443b73..a68013f5 100644 --- a/frontend/src/modules/production-modules/production-module.routing.ts +++ b/frontend/src/modules/production-modules/production-module.routing.ts @@ -17,7 +17,7 @@ const routes: Routes = [ children: [ {path: '', redirectTo: 'overview', pathMatch: 'full'}, {path: 'overview', component: ModuleOverviewComponent}, - {path: 'graph-visualization', component: ModuleGraphVisuComponent}, + // {path: 'graph-visualization', component: ModuleGraphVisuComponent}, // Note that graph visu is passed to the graph visu module {path: 'register', component: ModuleRegistrationComponent}, ] } diff --git a/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.html b/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.html index afd8c203..bae589fd 100644 --- a/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.html +++ b/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.html @@ -1,26 +1,26 @@

Mtp-Mapping-Settings

-
-
-
-
-
- URL: -
- +
+
+
+
+
+ URL: +
+ +
+
+
+
+
+ +
+
+

Server not reachable

+
-
-
-
-
- -
-
-

Server not reachable

-
-
diff --git a/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.ts b/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.ts index 318558be..b01b2686 100644 --- a/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.ts +++ b/frontend/src/modules/skillmex-configuration/subcomponents/mtp-mapping-settings.component.ts @@ -7,7 +7,6 @@ import {MappingServiceConfig} from '@shared/models/mappings/MappingServiceConfig selector: 'mtp-mapping-settings', templateUrl: './mtp-mapping-settings.component.html', }) - export class MtpMappingSettingsComponent implements OnInit{ url = "asd"; diff --git a/frontend/src/shared/index.ts b/frontend/src/shared/index.ts index ae60048e..5790705b 100644 --- a/frontend/src/shared/index.ts +++ b/frontend/src/shared/index.ts @@ -1,3 +1,4 @@ export * from './modules'; export * from './pipes/shared-pipes.module'; export * from './guard'; + diff --git a/frontend/src/shared/services/capability.service.ts b/frontend/src/shared/services/capability.service.ts index f9ff0c0a..686647c3 100644 --- a/frontend/src/shared/services/capability.service.ts +++ b/frontend/src/shared/services/capability.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { CapabilityDto } from '@shared/models/capability/Capability'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { map } from 'rxjs/operators'; import { SkillService } from './skill.service'; import { Capability } from '../models/Capability'; @@ -55,7 +55,8 @@ export class CapabilityService { addCapability(ontologyString: string): Observable> { const apiURL = `${this.apiRoot}/capabilities`; - return this.http.post(apiURL, ontologyString); + const headers = new HttpHeaders({"content-type": "text/turtle"}); + return this.http.post(apiURL, ontologyString, {headers: headers}); } addMtpCapability(ontologyFile: File): Observable{ diff --git a/frontend/src/shared/services/module.service.ts b/frontend/src/shared/services/module.service.ts index 8490a551..2b5ebb67 100644 --- a/frontend/src/shared/services/module.service.ts +++ b/frontend/src/shared/services/module.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { HttpClient } from "@angular/common/http"; +import { HttpClient, HttpHeaders } from "@angular/common/http"; import { Observable, Observer } from "rxjs"; import { ProductionModuleDto } from "@shared/models/production-module/ProductionModule"; import { map, take } from 'rxjs/operators'; @@ -84,16 +84,10 @@ export class ModuleService { } addModule(ontologyString: string): Observable> { const apiURL = `${this.apiRoot}/modules`; - return this.http.post(apiURL, ontologyString); + const headers = new HttpHeaders({"content-type": "text/turtle"}); + return this.http.post(apiURL, ontologyString, {headers: headers}); } - // addMtpModule(ontologyFile: File): Observable{ - // const apiURL= `${this.apiRoot}/MtpModules`; - // console.log("Module posted (mtp)"); - // return this.http.post(apiURL, ontologyFile); - // const testString="testtesttest"; - // //return this.http.post(apiURL,testString); - // } addMtpModule(ontologyFile: File): Observable{ const apiURL = `${this.apiRoot}/Mtp`; const formData= new FormData; diff --git a/frontend/src/shared/services/skill.service.ts b/frontend/src/shared/services/skill.service.ts index c1005f09..0e16adcd 100644 --- a/frontend/src/shared/services/skill.service.ts +++ b/frontend/src/shared/services/skill.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { map } from 'rxjs/operators'; import { SkillDto } from '@shared/models/skill/Skill'; import { Skill } from '../models/Skill'; @@ -71,7 +71,8 @@ export class SkillService { } addSkill(ontologyString: string): Observable> { const apiURL = `${this.apiRoot}/skills`; - return this.http.post(apiURL, ontologyString); + const headers = new HttpHeaders({"content-type": "text/turtle"}); + return this.http.post(apiURL, ontologyString, {headers: headers}); } diff --git a/frontend/typings.d.ts b/frontend/typings.d.ts deleted file mode 100644 index ef5c7bd6..00000000 --- a/frontend/typings.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/* SystemJS module definition */ -declare var module: NodeModule; -interface NodeModule { - id: string; -}