From 05b4e0cdcf45c6d69a1a0a4e0fa9cbe1e619f329 Mon Sep 17 00:00:00 2001 From: Aroy-Art Date: Thu, 15 May 2025 15:32:21 +0200 Subject: [PATCH 1/3] Add: charting lib --- package-lock.json | 436 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 +- 2 files changed, 426 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae79ec3..7b79d01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "@angular/platform-browser": "^19.2.0", "@angular/platform-browser-dynamic": "^19.2.0", "@angular/router": "^19.2.0", + "chart.js": "^4.4.9", + "ng2-charts": "^8.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" @@ -493,6 +495,22 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/@angular/cdk": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.2.15.tgz", + "integrity": "sha512-srM0O4oVPvMIbv1m+fU3D0X2ZK0Q7raggCD7jcb+d+pXoPESqI91Hn8FIhA2OCbw0vJWJ/Mly8lskmIb8RNLcQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "parse5": "^7.1.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0 || ^20.0.0", + "@angular/core": "^19.0.0 || ^20.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/@angular/cli": { "version": "19.2.7", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-19.2.7.tgz", @@ -3320,6 +3338,12 @@ "tslib": "2" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -4695,6 +4719,21 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.2.tgz", + "integrity": "sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", @@ -6237,6 +6276,18 @@ "dev": true, "license": "MIT" }, + "node_modules/chart.js": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.9.tgz", + "integrity": "sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -7255,7 +7306,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -7733,9 +7783,9 @@ } }, "node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9749,6 +9799,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -10472,6 +10528,24 @@ "dev": true, "license": "MIT" }, + "node_modules/ng2-charts": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-8.0.0.tgz", + "integrity": "sha512-nofsNHI2Zt+EAwT+BJBVg0kgOhNo9ukO4CxULlaIi7VwZSr7I1km38kWSoU41Oq6os6qqIh5srnL+CcV+RFPFA==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": ">=19.0.0", + "@angular/common": ">=19.0.0", + "@angular/core": ">=19.0.0", + "@angular/platform-browser": ">=19.0.0", + "chart.js": "^3.4.0 || ^4.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/node-addon-api": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", @@ -11146,7 +11220,6 @@ "version": "7.2.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", - "dev": true, "license": "MIT", "dependencies": { "entities": "^4.5.0" @@ -13270,13 +13343,13 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -13645,16 +13718,19 @@ } }, "node_modules/vite": { - "version": "6.2.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", - "integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", "postcss": "^8.5.3", - "rollup": "^4.30.1" + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" @@ -13717,6 +13793,299 @@ } } }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.2.tgz", + "integrity": "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.2.tgz", + "integrity": "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.2.tgz", + "integrity": "sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.2.tgz", + "integrity": "sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.2.tgz", + "integrity": "sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.2.tgz", + "integrity": "sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.2.tgz", + "integrity": "sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.2.tgz", + "integrity": "sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.2.tgz", + "integrity": "sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.2.tgz", + "integrity": "sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.2.tgz", + "integrity": "sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.2.tgz", + "integrity": "sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.2.tgz", + "integrity": "sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.2.tgz", + "integrity": "sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz", + "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.2.tgz", + "integrity": "sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.2.tgz", + "integrity": "sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.2.tgz", + "integrity": "sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.2.tgz", + "integrity": "sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/vite/node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/vite/node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -13747,6 +14116,47 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/vite/node_modules/rollup": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.2.tgz", + "integrity": "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.40.2", + "@rollup/rollup-android-arm64": "4.40.2", + "@rollup/rollup-darwin-arm64": "4.40.2", + "@rollup/rollup-darwin-x64": "4.40.2", + "@rollup/rollup-freebsd-arm64": "4.40.2", + "@rollup/rollup-freebsd-x64": "4.40.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", + "@rollup/rollup-linux-arm-musleabihf": "4.40.2", + "@rollup/rollup-linux-arm64-gnu": "4.40.2", + "@rollup/rollup-linux-arm64-musl": "4.40.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", + "@rollup/rollup-linux-riscv64-gnu": "4.40.2", + "@rollup/rollup-linux-riscv64-musl": "4.40.2", + "@rollup/rollup-linux-s390x-gnu": "4.40.2", + "@rollup/rollup-linux-x64-gnu": "4.40.2", + "@rollup/rollup-linux-x64-musl": "4.40.2", + "@rollup/rollup-win32-arm64-msvc": "4.40.2", + "@rollup/rollup-win32-ia32-msvc": "4.40.2", + "@rollup/rollup-win32-x64-msvc": "4.40.2", + "fsevents": "~2.3.2" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", diff --git a/package.json b/package.json index 0f3aa75..77201ed 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "@angular/platform-browser": "^19.2.0", "@angular/platform-browser-dynamic": "^19.2.0", "@angular/router": "^19.2.0", + "chart.js": "^4.4.9", + "ng2-charts": "^8.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" @@ -34,4 +36,4 @@ "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.7.2" } -} +} \ No newline at end of file From eeabe3c41db8571cc0168b88688af8ffbd8252c2 Mon Sep 17 00:00:00 2001 From: Aroy-Art Date: Thu, 15 May 2025 15:53:34 +0200 Subject: [PATCH 2/3] Add: first working version --- src/app/app.component.css | 84 ++++ src/app/app.component.html | 391 +++--------------- src/app/app.component.spec.ts | 29 -- src/app/app.component.ts | 70 +++- src/app/app.config.ts | 3 +- src/app/app.module.ts | 25 ++ .../energy-chart/energy-chart.component.css | 4 + .../energy-chart/energy-chart.component.html | 8 + .../energy-chart/energy-chart.component.ts | 105 +++++ src/app/energy-price.service.ts | 32 ++ src/main.ts | 11 +- 11 files changed, 394 insertions(+), 368 deletions(-) delete mode 100644 src/app/app.component.spec.ts create mode 100644 src/app/app.module.ts create mode 100644 src/app/energy-chart/energy-chart.component.css create mode 100644 src/app/energy-chart/energy-chart.component.html create mode 100644 src/app/energy-chart/energy-chart.component.ts create mode 100644 src/app/energy-price.service.ts diff --git a/src/app/app.component.css b/src/app/app.component.css index e69de29..77fa3f9 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -0,0 +1,84 @@ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + font-family: Arial, sans-serif; +} + +header { + margin-bottom: 20px; + text-align: center; +} + +h1 { + color: #333; +} + +.controls { + display: flex; + justify-content: space-between; + margin-bottom: 20px; + flex-wrap: wrap; + gap: 10px; +} + +.form-group { + margin-bottom: 10px; + flex: 1; + min-width: 200px; +} + +label { + display: block; + margin-bottom: 5px; + font-weight: bold; +} + +select, input { + width: 100%; + padding: 8px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.chart-container { + background-color: #f9f9f9; + border-radius: 8px; + padding: 20px; + min-height: 400px; + margin-bottom: 20px; +} + +.loading, .error { + display: flex; + justify-content: center; + align-items: center; + height: 400px; +} + +.error { + color: #d9534f; +} + +.price-list { + margin-top: 30px; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + padding: 10px; + text-align: left; + border-bottom: 1px solid #ddd; +} + +th { + background-color: #f2f2f2; +} + +tr:hover { + background-color: #f5f5f5; +} diff --git a/src/app/app.component.html b/src/app/app.component.html index 36093e1..2c16ce5 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,336 +1,69 @@ - - - - - - - - +
+
+

{{ title }}

+
- - -
-
-
- -

Hello, {{ title }}

-

Congratulations! Your app is running. 🎉

-
- -
-
- @for (item of [ - { title: 'Explore the Docs', link: 'https://angular.dev' }, - { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, - { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, - { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, - { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, - ]; track item.title) { - - {{ item.title }} - - - - +
+
+ + +
+ +
+ +
-
- - - - - - - +
+ @if (loading) { +
+

Loading energy price data...

+
+ } + @if (error) { +
+

{{ error }}

+
+ } - + @if (!loading && !error) { + + } +
+ + @if (!loading && !error && priceData.length > 0) { +
+

Hour-by-hour prices

+ + + + + + + + + + @for (price of priceData; track price.time_start) { + + + + + + } + +
TimeSEK/kWhEUR/kWh
{{ price.time_start | date:'HH:00' }} - {{ price.time_end | date:'HH:00' }}{{ price.SEK_per_kWh | number:'1.2-4' }}{{ price.EUR_per_kWh | number:'1.2-4' }}
+
+ } diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts deleted file mode 100644 index 5558c4f..0000000 --- a/src/app/app.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [AppComponent], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have the 'Angular-DotIO' title`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('Angular-DotIO'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Angular-DotIO'); - }); -}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index fbb0c2d..8e98ba0 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,12 +1,70 @@ -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; +import { Component, OnInit, inject } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { EnergyPriceService, EnergyPrice } from './energy-price.service'; +import { EnergyChartComponent } from './energy-chart/energy-chart.component'; @Component({ selector: 'app-root', - imports: [RouterOutlet], templateUrl: './app.component.html', - styleUrl: './app.component.css' + styleUrls: ['./app.component.css'], + standalone: true, + imports: [CommonModule, FormsModule, EnergyChartComponent] }) -export class AppComponent { - title = 'Angular-DotIO'; +export class AppComponent implements OnInit { + title = 'Energy Price Dashboard'; + priceData: EnergyPrice[] = []; + loading = true; + error = ''; + + // Default values + selectedDate = new Date(); + selectedRegion = 'SE3'; // Stockholm / Södra Mellansverige as default + + regions = [ + { value: 'SE1', label: 'Luleå / Norra Sverige' }, + { value: 'SE2', label: 'Sundsvall / Norra Mellansverige' }, + { value: 'SE3', label: 'Stockholm / Södra Mellansverige' }, + { value: 'SE4', label: 'Malmö / Södra Sverige' } + ]; + + private energyPriceService = inject(EnergyPriceService); + + ngOnInit() { + this.loadPriceData(); + } + + loadPriceData() { + this.loading = true; + this.error = ''; + + const { year, month, day } = this.energyPriceService.formatDate(this.selectedDate); + + this.energyPriceService.getPrices(year, month, day, this.selectedRegion) + .subscribe({ + next: (data) => { + this.priceData = data; + this.loading = false; + }, + error: (err) => { + this.error = 'Failed to load energy price data. Please try again later.'; + this.loading = false; + console.error('Error fetching price data:', err); + } + }); + } + + onRegionChange() { + this.loadPriceData(); + } + + onDateChange(event: any) { + this.selectedDate = new Date(event.target.value); + this.loadPriceData(); + } + + get maxDate(): string { + const today = new Date(); + return today.toISOString().split('T')[0]; + } } diff --git a/src/app/app.config.ts b/src/app/app.config.ts index a1e7d6f..6896639 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -2,7 +2,8 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; +import { provideCharts, withDefaultRegisterables } from 'ng2-charts'; export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] + providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideCharts(withDefaultRegisterables())] }; diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 0000000..afe33a2 --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { HttpClientModule } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { NgChartsModule } from 'ng2-charts'; + +import { AppComponent } from './app.component'; +import { EnergyPriceService } from './energy-price.service'; +import { EnergyChartComponent } from './energy-chart/energy-chart.component'; + +@NgModule({ + declarations: [ + AppComponent, + EnergyChartComponent + ], + imports: [ + BrowserModule, + HttpClientModule, + FormsModule, + NgChartsModule + ], + providers: [EnergyPriceService], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/src/app/energy-chart/energy-chart.component.css b/src/app/energy-chart/energy-chart.component.css new file mode 100644 index 0000000..cf8b246 --- /dev/null +++ b/src/app/energy-chart/energy-chart.component.css @@ -0,0 +1,4 @@ +.chart-wrapper { + height: 400px; + width: 100%; +} diff --git a/src/app/energy-chart/energy-chart.component.html b/src/app/energy-chart/energy-chart.component.html new file mode 100644 index 0000000..f0665d3 --- /dev/null +++ b/src/app/energy-chart/energy-chart.component.html @@ -0,0 +1,8 @@ +
+ + +
+ diff --git a/src/app/energy-chart/energy-chart.component.ts b/src/app/energy-chart/energy-chart.component.ts new file mode 100644 index 0000000..dc9849e --- /dev/null +++ b/src/app/energy-chart/energy-chart.component.ts @@ -0,0 +1,105 @@ +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ChartConfiguration, ChartData, ChartType } from 'chart.js'; +import { BaseChartDirective } from 'ng2-charts'; +import { EnergyPrice } from '../energy-price.service'; + +@Component({ + selector: 'app-energy-chart', + templateUrl: './energy-chart.component.html', + styleUrls: ['./energy-chart.component.css'], + standalone: true, + imports: [CommonModule, BaseChartDirective] +}) +export class EnergyChartComponent implements OnChanges { + @Input() priceData: EnergyPrice[] = []; + + // Chart configuration + public lineChartType: ChartType = 'line'; + + public lineChartData: ChartData<'line'> = { + datasets: [], + labels: [] + }; + + public lineChartOptions: ChartConfiguration['options'] = { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + title: { + display: true, + text: 'Time' + } + }, + y: { + title: { + display: true, + text: 'Price (SEK per kWh)' + }, + beginAtZero: true + } + }, + plugins: { + legend: { + display: true, + }, + tooltip: { + callbacks: { + label: function(context) { + let label = context.dataset.label || ''; + if (label) { + label += ': '; + } + if (context.parsed.y !== null) { + label += context.parsed.y.toFixed(2) + ' SEK/kWh'; + } + return label; + } + } + } + } + }; + + ngOnChanges(changes: SimpleChanges): void { + if (changes['priceData'] && this.priceData) { + this.updateChartData(); + } + } + + private updateChartData(): void { + // Extract time labels and price values + const labels = this.priceData.map(item => { + const startTime = new Date(item.time_start); + return startTime.getHours() + ':00'; + }); + + const sekPrices = this.priceData.map(item => item.SEK_per_kWh); + const eurPrices = this.priceData.map(item => item.EUR_per_kWh); + + // Update chart data + this.lineChartData = { + labels: labels, + datasets: [ + { + data: sekPrices, + label: 'SEK per kWh', + backgroundColor: 'rgba(66, 133, 244, 0.2)', + borderColor: 'rgb(66, 133, 244)', + pointBackgroundColor: 'rgb(66, 133, 244)', + fill: 'origin', + tension: 0.4 + }, + { + data: eurPrices, + label: 'EUR per kWh', + backgroundColor: 'rgba(15, 157, 88, 0.2)', + borderColor: 'rgb(15, 157, 88)', + pointBackgroundColor: 'rgb(15, 157, 88)', + fill: 'origin', + tension: 0.4 + } + ] + }; + } +} diff --git a/src/app/energy-price.service.ts b/src/app/energy-price.service.ts new file mode 100644 index 0000000..33440e5 --- /dev/null +++ b/src/app/energy-price.service.ts @@ -0,0 +1,32 @@ +import { Injectable, inject } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +export interface EnergyPrice { + SEK_per_kWh: number; + EUR_per_kWh: number; + EXR: number; + time_start: string; + time_end: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class EnergyPriceService { + private apiBaseUrl = 'https://www.elprisetjustnu.se/api/v1/prices'; + private http = inject(HttpClient); + + getPrices(year: string, month: string, day: string, priceClass: string): Observable { + const url = `${this.apiBaseUrl}/${year}/${month}-${day}_${priceClass}.json`; + return this.http.get(url); + } + + formatDate(date: Date): { year: string, month: string, day: string } { + const year = date.getFullYear().toString(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + + return { year, month, day }; + } +} diff --git a/src/main.ts b/src/main.ts index 35b00f3..4e6be2b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,11 @@ import { bootstrapApplication } from '@angular/platform-browser'; -import { appConfig } from './app/app.config'; +import { provideHttpClient } from '@angular/common/http'; +import { provideCharts, withDefaultRegisterables } from 'ng2-charts'; import { AppComponent } from './app/app.component'; -bootstrapApplication(AppComponent, appConfig) - .catch((err) => console.error(err)); +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient(), + provideCharts(withDefaultRegisterables()) + ] +}).catch(err => console.error(err)); From 6f88f96de85021d12b452b41a499ea30987a6386 Mon Sep 17 00:00:00 2001 From: Aroy-Art Date: Thu, 15 May 2025 15:54:11 +0200 Subject: [PATCH 3/3] Disable: angular cli analytics --- angular.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/angular.json b/angular.json index 065174f..798cd85 100644 --- a/angular.json +++ b/angular.json @@ -92,5 +92,8 @@ } } } + }, + "cli": { + "analytics": false } }