From 745d50d861a180589951dac78e08fda63c6ae565 Mon Sep 17 00:00:00 2001 From: arturovt Date: Sat, 30 Jan 2021 00:02:43 +0200 Subject: [PATCH] chore: format code with Prettier --- package-lock.json | 966 ++++++++++- package.json | 22 +- projects/ng-circle-progress/ng-package.json | 2 +- projects/ng-circle-progress/package.json | 2 +- .../src/lib/ng-circle-progress.component.ts | 1479 +++++++++-------- .../src/lib/ng-circle-progress.module.ts | 21 +- projects/ng-circle-progress/tsconfig.lib.json | 10 +- .../ng-circle-progress/tsconfig.spec.json | 13 +- projects/ng-circle-progress/tslint.json | 14 +- src/app/app.component.html | 276 ++- src/app/app.component.spec.ts | 8 +- src/app/app.component.ts | 117 +- src/app/app.module.ts | 18 +- 13 files changed, 2007 insertions(+), 941 deletions(-) diff --git a/package-lock.json b/package-lock.json index ff86c6e..a69bce3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "ng-circle-progress-library", - "version": "0.0.0", + "name": "ng-circle-progress", + "version": "1.6.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2055,6 +2055,12 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "@types/q": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", @@ -2647,6 +2653,12 @@ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", @@ -3378,6 +3390,12 @@ } } }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -3438,6 +3456,56 @@ "integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==", "dev": true }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -3619,6 +3687,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -4301,6 +4375,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -4829,6 +4909,23 @@ "tapable": "^1.0.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + } + } + }, "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", @@ -5526,6 +5623,15 @@ "locate-path": "^3.0.0" } }, + "find-versions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", + "dev": true, + "requires": { + "semver-regex": "^3.1.2" + } + }, "flatted": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", @@ -5668,6 +5774,12 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -6200,6 +6312,12 @@ } } }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, "humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -6209,6 +6327,168 @@ "ms": "^2.0.0" } }, + "husky": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", + "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.6.0", + "cosmiconfig": "^7.0.0", + "find-versions": "^4.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^5.0.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "iconv-lite": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", @@ -6764,6 +7044,12 @@ "has-symbols": "^1.0.1" } }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", @@ -7442,68 +7728,388 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "optional": true + "optional": true + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } + } + }, + "less-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-6.2.0.tgz", + "integrity": "sha512-Cl5h95/Pz/PWub/tCBgT1oNMFeH1WTD33piG80jn5jr12T4XbxZcjThwNXDQ7AG649WEynuIzO4b0+2Tn9Qolg==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "less": "^3.11.3", + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "license-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-JK/DXrtN6UeYQSgkg5q1+pgJ8aiKPL9tnz9Wzw+Ikkf+8mJxG56x6t8O+OH/tAeF/5NREnelTEMyFtbJNkjH4w==", + "dev": true, + "requires": { + "@types/webpack-sources": "^0.1.5", + "webpack-sources": "^1.2.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "lint-staged": { + "version": "10.5.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.3.tgz", + "integrity": "sha512-TanwFfuqUBLufxCc3RUtFEkFraSPNR3WzWcGF39R3f2J7S9+iF9W0KTVLfSy09lYGmZS5NDCxjNvhGMSJyFCWg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "cli-truncate": "^2.1.0", + "commander": "^6.2.0", + "cosmiconfig": "^7.0.0", + "debug": "^4.2.0", + "dedent": "^0.7.0", + "enquirer": "^2.3.6", + "execa": "^4.1.0", + "listr2": "^3.2.2", + "log-symbols": "^4.0.0", + "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", + "please-upgrade-node": "^3.2.0", + "string-argv": "0.3.1", + "stringify-object": "^3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true + }, + "cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "listr2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.3.0.tgz", + "integrity": "sha512-G9IFI/m65icgVlifS0wMQnvn35/8VJGzEb3crpE4NnaegQYQOn/wP7yqi9TTJQ/eoxme4UaPbffBK1XqKP/DOg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "cli-truncate": "^2.1.0", + "figures": "^3.2.0", + "indent-string": "^4.0.0", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rxjs": "^6.6.3", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } } } }, - "less-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-6.2.0.tgz", - "integrity": "sha512-Cl5h95/Pz/PWub/tCBgT1oNMFeH1WTD33piG80jn5jr12T4XbxZcjThwNXDQ7AG649WEynuIzO4b0+2Tn9Qolg==", - "dev": true, - "requires": { - "clone": "^2.1.2", - "less": "^3.11.3", - "loader-utils": "^2.0.0", - "schema-utils": "^2.7.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levenary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", - "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", - "dev": true, - "requires": { - "leven": "^3.1.0" - } - }, - "license-webpack-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.3.0.tgz", - "integrity": "sha512-JK/DXrtN6UeYQSgkg5q1+pgJ8aiKPL9tnz9Wzw+Ikkf+8mJxG56x6t8O+OH/tAeF/5NREnelTEMyFtbJNkjH4w==", - "dev": true, - "requires": { - "@types/webpack-sources": "^0.1.5", - "webpack-sources": "^1.2.0" - } - }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "requires": { - "immediate": "~3.0.5" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, "loader-runner": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", @@ -7621,6 +8227,104 @@ } } }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, "log4js": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", @@ -8791,6 +9495,12 @@ "is-wsl": "^2.1.1" } }, + "opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "dev": true + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -9171,6 +9881,23 @@ "readable-stream": "^2.1.5" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, "parse-asn1": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", @@ -9346,6 +10073,15 @@ "find-up": "^3.0.0" } }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, "pnp-webpack-plugin": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", @@ -10035,6 +10771,12 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "dev": true }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -11322,6 +12064,12 @@ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, "semver-dsl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", @@ -11356,6 +12104,12 @@ } } }, + "semver-regex": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz", + "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==", + "dev": true + }, "send": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", @@ -11579,6 +12333,49 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } + } + }, "smart-buffer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", @@ -12242,6 +13039,12 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -12341,6 +13144,25 @@ "safe-buffer": "~5.1.0" } }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + } + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -12356,6 +13178,12 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "style-loader": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.2.1.tgz", @@ -14153,6 +14981,12 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", + "dev": true + }, "worker-farm": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", @@ -14283,6 +15117,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "dev": true + }, "yargs": { "version": "13.3.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", @@ -14331,6 +15171,12 @@ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, "zone.js": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", diff --git a/package.json b/package.json index cdd666a..135ae66 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,11 @@ "@angular-devkit/build-angular": "~0.1001.3", "@angular/cli": "~10.1.3", "@angular/compiler-cli": "~10.1.3", - "@types/node": "^12.11.1", "@types/jasmine": "~3.5.0", "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", "codelyzer": "^6.0.0", + "husky": "^4.3.8", "jasmine-core": "~3.6.0", "jasmine-spec-reporter": "~5.0.0", "karma": "~5.0.0", @@ -44,10 +45,29 @@ "karma-coverage-istanbul-reporter": "~3.0.2", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", + "lint-staged": "^10.5.3", "ng-packagr": "^10.1.0", + "prettier": "^2.2.1", "protractor": "~7.0.0", "ts-node": "~8.3.0", "tslint": "~6.1.0", "typescript": "~4.0.2" + }, + "prettier": { + "endOfLine": "lf", + "arrowParens": "avoid", + "singleQuote": true, + "printWidth": 100, + "trailingComma": "all" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*.{ts,js,json,html}": [ + "prettier --write" + ] } } diff --git a/projects/ng-circle-progress/ng-package.json b/projects/ng-circle-progress/ng-package.json index 9877db4..979cdcc 100644 --- a/projects/ng-circle-progress/ng-package.json +++ b/projects/ng-circle-progress/ng-package.json @@ -4,4 +4,4 @@ "lib": { "entryFile": "src/public-api.ts" } -} \ No newline at end of file +} diff --git a/projects/ng-circle-progress/package.json b/projects/ng-circle-progress/package.json index f7efe13..c93c4bd 100644 --- a/projects/ng-circle-progress/package.json +++ b/projects/ng-circle-progress/package.json @@ -27,4 +27,4 @@ "dependencies": { "tslib": "^2.0.0" } -} \ No newline at end of file +} diff --git a/projects/ng-circle-progress/src/lib/ng-circle-progress.component.ts b/projects/ng-circle-progress/src/lib/ng-circle-progress.component.ts index 06d637a..575f02f 100644 --- a/projects/ng-circle-progress/src/lib/ng-circle-progress.component.ts +++ b/projects/ng-circle-progress/src/lib/ng-circle-progress.component.ts @@ -1,732 +1,823 @@ -import { Component, EventEmitter, Input, OnChanges, Output, Inject, OnInit, OnDestroy, ElementRef, SimpleChanges } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + OnChanges, + Output, + Inject, + OnInit, + OnDestroy, + ElementRef, + SimpleChanges, +} from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { Subscription, timer } from 'rxjs'; export interface CircleProgressOptionsInterface { - class?: string; - backgroundGradient?: boolean; - backgroundColor?: string; - backgroundGradientStopColor?: string; - backgroundOpacity?: number; - backgroundStroke?: string; - backgroundStrokeWidth?: number; - backgroundPadding?: number; - percent?: number; - radius?: number; - space?: number; - toFixed?: number; - maxPercent?: number; - renderOnClick?: boolean; - units?: string; - unitsFontSize?: string; - unitsFontWeight?: string; - unitsColor?: string; - outerStrokeGradient?: boolean; - outerStrokeWidth?: number; - outerStrokeColor?: string; - outerStrokeGradientStopColor?: string; - outerStrokeLinecap?: string; - innerStrokeColor?: string; - innerStrokeWidth?: number; - titleFormat?: Function; - title?: string | Array; - titleColor?: string; - titleFontSize?: string; - titleFontWeight?: string; - subtitleFormat?: Function; - subtitle?: string | Array; - subtitleColor?: string; - subtitleFontSize?: string; - subtitleFontWeight?: string; - imageSrc?: string; - imageHeight?: number; - imageWidth?: number; - animation?: boolean; - animateTitle?: boolean; - animateSubtitle?: boolean; - animationDuration?: number; - showTitle?: boolean; - showSubtitle?: boolean; - showUnits?: boolean; - showImage?: boolean; - showBackground?: boolean; - showInnerStroke?: boolean; - clockwise?: boolean; - responsive?: boolean; - startFromZero?: boolean; - showZeroOuterStroke?: boolean; - lazy?: boolean; + class?: string; + backgroundGradient?: boolean; + backgroundColor?: string; + backgroundGradientStopColor?: string; + backgroundOpacity?: number; + backgroundStroke?: string; + backgroundStrokeWidth?: number; + backgroundPadding?: number; + percent?: number; + radius?: number; + space?: number; + toFixed?: number; + maxPercent?: number; + renderOnClick?: boolean; + units?: string; + unitsFontSize?: string; + unitsFontWeight?: string; + unitsColor?: string; + outerStrokeGradient?: boolean; + outerStrokeWidth?: number; + outerStrokeColor?: string; + outerStrokeGradientStopColor?: string; + outerStrokeLinecap?: string; + innerStrokeColor?: string; + innerStrokeWidth?: number; + titleFormat?: Function; + title?: string | Array; + titleColor?: string; + titleFontSize?: string; + titleFontWeight?: string; + subtitleFormat?: Function; + subtitle?: string | Array; + subtitleColor?: string; + subtitleFontSize?: string; + subtitleFontWeight?: string; + imageSrc?: string; + imageHeight?: number; + imageWidth?: number; + animation?: boolean; + animateTitle?: boolean; + animateSubtitle?: boolean; + animationDuration?: number; + showTitle?: boolean; + showSubtitle?: boolean; + showUnits?: boolean; + showImage?: boolean; + showBackground?: boolean; + showInnerStroke?: boolean; + clockwise?: boolean; + responsive?: boolean; + startFromZero?: boolean; + showZeroOuterStroke?: boolean; + lazy?: boolean; } export class CircleProgressOptions implements CircleProgressOptionsInterface { - class = ''; - backgroundGradient = false; - backgroundColor = 'transparent'; - backgroundGradientStopColor = 'transparent'; - backgroundOpacity = 1; - backgroundStroke = 'transparent'; - backgroundStrokeWidth = 0; - backgroundPadding = 5; - percent = 0; - radius = 90; - space = 4; - toFixed = 0; - maxPercent = 1000; - renderOnClick = true; - units = '%'; - unitsFontSize = '10'; - unitsFontWeight = 'normal'; - unitsColor = '#444444'; - outerStrokeGradient = false; - outerStrokeWidth = 8; - outerStrokeColor = '#78C000'; - outerStrokeGradientStopColor = 'transparent'; - outerStrokeLinecap = 'round'; - innerStrokeColor = '#C7E596'; - innerStrokeWidth = 4; - titleFormat = undefined; - title: string | Array = 'auto'; - titleColor = '#444444'; - titleFontSize = '20'; - titleFontWeight = 'normal'; - subtitleFormat = undefined; - subtitle: string | Array = 'progress'; - subtitleColor = '#A9A9A9'; - subtitleFontSize = '10'; - subtitleFontWeight = 'normal'; - imageSrc = undefined; - imageHeight = undefined; - imageWidth = undefined; - animation = true; - animateTitle = true; - animateSubtitle = false; - animationDuration = 500; - showTitle = true; - showSubtitle = true; - showUnits = true; - showImage = false; - showBackground = true; - showInnerStroke = true; - clockwise = true; - responsive = false; - startFromZero = true; - showZeroOuterStroke = true; - lazy = false; + class = ''; + backgroundGradient = false; + backgroundColor = 'transparent'; + backgroundGradientStopColor = 'transparent'; + backgroundOpacity = 1; + backgroundStroke = 'transparent'; + backgroundStrokeWidth = 0; + backgroundPadding = 5; + percent = 0; + radius = 90; + space = 4; + toFixed = 0; + maxPercent = 1000; + renderOnClick = true; + units = '%'; + unitsFontSize = '10'; + unitsFontWeight = 'normal'; + unitsColor = '#444444'; + outerStrokeGradient = false; + outerStrokeWidth = 8; + outerStrokeColor = '#78C000'; + outerStrokeGradientStopColor = 'transparent'; + outerStrokeLinecap = 'round'; + innerStrokeColor = '#C7E596'; + innerStrokeWidth = 4; + titleFormat = undefined; + title: string | Array = 'auto'; + titleColor = '#444444'; + titleFontSize = '20'; + titleFontWeight = 'normal'; + subtitleFormat = undefined; + subtitle: string | Array = 'progress'; + subtitleColor = '#A9A9A9'; + subtitleFontSize = '10'; + subtitleFontWeight = 'normal'; + imageSrc = undefined; + imageHeight = undefined; + imageWidth = undefined; + animation = true; + animateTitle = true; + animateSubtitle = false; + animationDuration = 500; + showTitle = true; + showSubtitle = true; + showUnits = true; + showImage = false; + showBackground = true; + showInnerStroke = true; + clockwise = true; + responsive = false; + startFromZero = true; + showZeroOuterStroke = true; + lazy = false; } /** @dynamic Prevent compiling error when using type `Document` https://github.com/angular/angular/issues/20351 */ @Component({ - selector: 'circle-progress', - template: ` - - - - - - - - - - - - - - - - - - - - - - - {{tspan.span}} - - {{svg.units.text}} - - {{tspan.span}} - - - - - ` + selector: 'circle-progress', + template: ` + + + + + + + + + + + + + + + + + + + + + + + + {{ tspan.span }} + + + + {{ svg.units.text }} + + + + {{ tspan.span }} + + + + + + `, }) export class CircleProgressComponent implements OnChanges, OnInit, OnDestroy { - - @Output() onClick: EventEmitter = new EventEmitter(); - - @Input() name: string; - @Input() class: string; - @Input() backgroundGradient: boolean; - @Input() backgroundColor: string; - @Input() backgroundGradientStopColor: String; - @Input() backgroundOpacity: number; - @Input() backgroundStroke: string; - @Input() backgroundStrokeWidth: number; - @Input() backgroundPadding: number; - - @Input() radius: number; - @Input() space: number; - @Input() percent: number; - @Input() toFixed: number; - @Input() maxPercent: number; - @Input() renderOnClick: boolean; - - @Input() units: string; - @Input() unitsFontSize: string; - @Input() unitsFontWeight: string; - @Input() unitsColor: string; - - @Input() outerStrokeGradient: boolean; - @Input() outerStrokeWidth: number; - @Input() outerStrokeColor: string; - @Input() outerStrokeGradientStopColor: String; - @Input() outerStrokeLinecap: string; - - @Input() innerStrokeColor: string; - @Input() innerStrokeWidth: string | number; - - @Input() titleFormat: Function; - @Input() title: string | Array; - @Input() titleColor: string; - @Input() titleFontSize: string; - @Input() titleFontWeight: string; - - @Input() subtitleFormat: Function; - @Input() subtitle: string | string[]; - @Input() subtitleColor: string; - @Input() subtitleFontSize: string; - @Input() subtitleFontWeight: string; - - @Input() imageSrc: string; - @Input() imageHeight: number; - @Input() imageWidth: number; - - @Input() animation: boolean; - @Input() animateTitle: boolean; - @Input() animateSubtitle: boolean; - @Input() animationDuration: number; - - @Input() showTitle: boolean; - @Input() showSubtitle: boolean; - @Input() showUnits: boolean; - @Input() showImage: boolean; - @Input() showBackground: boolean; - @Input() showInnerStroke: boolean; - @Input() clockwise: boolean; - @Input() responsive: boolean; - @Input() startFromZero: boolean; - @Input() showZeroOuterStroke: boolean; - - @Input() lazy: boolean; - - @Input('options') templateOptions: CircleProgressOptions; - - // of component - svgElement: HTMLElement = null; - // whether is in viewport - isInViewport: Boolean = false; - // event for notifying viewport change caused by scrolling or resizing - onViewportChanged: EventEmitter<{ oldValue: Boolean, newValue: Boolean }> = new EventEmitter; - window: Window; - _viewportChangedSubscriber: Subscription = null; - - svg: any; - - options: CircleProgressOptions = new CircleProgressOptions(); - defaultOptions: CircleProgressOptions = new CircleProgressOptions(); - _lastPercent: number = 0; - _gradientUUID: string = null; - render = () => { - - this.applyOptions(); - - if (this.options.lazy) { - // Draw svg if it doesn't exist - this.svgElement === null && this.draw(this._lastPercent); - // Draw it only when it's in the viewport - if (this.isInViewport) { - // Draw it at the latest position when I am in. - if (this.options.animation && this.options.animationDuration > 0) { - this.animate(this._lastPercent, this.options.percent); - } else { - this.draw(this.options.percent); - } - this._lastPercent = this.options.percent; - } - } else { - if (this.options.animation && this.options.animationDuration > 0) { - this.animate(this._lastPercent, this.options.percent); - } else { - this.draw(this.options.percent); - } - this._lastPercent = this.options.percent; - } - }; - polarToCartesian = (centerX: number, centerY: number, radius: number, angleInDegrees: number) => { - let angleInRadius = angleInDegrees * Math.PI / 180; - let x = centerX + Math.sin(angleInRadius) * radius; - let y = centerY - Math.cos(angleInRadius) * radius; - return { x: x, y: y }; - }; - draw = (percent: number) => { - // make percent reasonable - percent = (percent === undefined) ? this.options.percent : Math.abs(percent); - // circle percent shouldn't be greater than 100%. - let circlePercent = (percent > 100) ? 100 : percent; - // determine box size - let boxSize = this.options.radius * 2 + this.options.outerStrokeWidth * 2; - if (this.options.showBackground) { - boxSize += (this.options.backgroundStrokeWidth * 2 + this.max(0, this.options.backgroundPadding * 2)); - } - // the centre of the circle - let centre = { x: boxSize / 2, y: boxSize / 2 }; - // the start point of the arc - let startPoint = { x: centre.x, y: centre.y - this.options.radius }; - // get the end point of the arc - let endPoint = this.polarToCartesian(centre.x, centre.y, this.options.radius, 360 * (this.options.clockwise ? - circlePercent : - (100 - circlePercent)) / 100); // #################### - // We'll get an end point with the same [x, y] as the start point when percent is 100%, so move x a little bit. - if (circlePercent === 100) { - endPoint.x = endPoint.x + (this.options.clockwise ? -0.01 : +0.01); - } - // largeArcFlag and sweepFlag - let largeArcFlag: any, sweepFlag: any; - if (circlePercent > 50) { - [largeArcFlag, sweepFlag] = this.options.clockwise ? [1, 1] : [1, 0]; - } else { - [largeArcFlag, sweepFlag] = this.options.clockwise ? [0, 1] : [0, 0]; - } - // percent may not equal the actual percent - let titlePercent = this.options.animateTitle ? percent : this.options.percent; - let titleTextPercent = titlePercent > this.options.maxPercent ? - `${this.options.maxPercent.toFixed(this.options.toFixed)}+` : titlePercent.toFixed(this.options.toFixed); - let subtitlePercent = this.options.animateSubtitle ? percent : this.options.percent; - // get title object - let title = { - x: centre.x, - y: centre.y, - textAnchor: 'middle', - color: this.options.titleColor, - fontSize: this.options.titleFontSize, - fontWeight: this.options.titleFontWeight, - texts: [], - tspans: [] - }; - // from v0.9.9, both title and titleFormat(...) may be an array of string. - if (this.options.titleFormat !== undefined && this.options.titleFormat.constructor.name === 'Function') { - let formatted = this.options.titleFormat(titlePercent); - if (formatted instanceof Array) { - title.texts = [...formatted]; - } else { - title.texts.push(formatted.toString()); - } - } else { - if (this.options.title === 'auto') { - title.texts.push(titleTextPercent); - } else { - if (this.options.title instanceof Array) { - title.texts = [...this.options.title] - } else { - title.texts.push(this.options.title.toString()); - } - } - } - // get subtitle object - let subtitle = { - x: centre.x, - y: centre.y, - textAnchor: 'middle', - color: this.options.subtitleColor, - fontSize: this.options.subtitleFontSize, - fontWeight: this.options.subtitleFontWeight, - texts: [], - tspans: [] - } - // from v0.9.9, both subtitle and subtitleFormat(...) may be an array of string. - if (this.options.subtitleFormat !== undefined && this.options.subtitleFormat.constructor.name === 'Function') { - let formatted = this.options.subtitleFormat(subtitlePercent); - if (formatted instanceof Array) { - subtitle.texts = [...formatted]; - } else { - subtitle.texts.push(formatted.toString()); - } - } else { - if (this.options.subtitle instanceof Array) { - subtitle.texts = [...this.options.subtitle] - } else { - subtitle.texts.push(this.options.subtitle.toString()); - } - } - // get units object - let units = { - text: `${this.options.units}`, - fontSize: this.options.unitsFontSize, - fontWeight: this.options.unitsFontWeight, - color: this.options.unitsColor - }; - // get total count of text lines to be shown - let rowCount = 0, rowNum = 1; - this.options.showTitle && (rowCount += title.texts.length); - this.options.showSubtitle && (rowCount += subtitle.texts.length); - // calc dy for each tspan for title - if (this.options.showTitle) { - for (let span of title.texts) { - title.tspans.push({ span: span, dy: this.getRelativeY(rowNum, rowCount) }); - rowNum++; - } - } - // calc dy for each tspan for subtitle - if (this.options.showSubtitle) { - for (let span of subtitle.texts) { - subtitle.tspans.push({ span: span, dy: this.getRelativeY(rowNum, rowCount) }) - rowNum++; - } - } - // create ID for gradient element - if (null === this._gradientUUID) { - this._gradientUUID = this.uuid(); - } - // Bring it all together - this.svg = { - viewBox: `0 0 ${boxSize} ${boxSize}`, - // Set both width and height to '100%' if it's responsive - width: this.options.responsive ? '100%' : boxSize, - height: this.options.responsive ? '100%' : boxSize, - backgroundCircle: { - cx: centre.x, - cy: centre.y, - r: this.options.radius + this.options.outerStrokeWidth / 2 + this.options.backgroundPadding, - fill: this.options.backgroundColor, - fillOpacity: this.options.backgroundOpacity, - stroke: this.options.backgroundStroke, - strokeWidth: this.options.backgroundStrokeWidth, - }, - path: { - // A rx ry x-axis-rotation large-arc-flag sweep-flag x y (https://developer.mozilla.org/en/docs/Web/SVG/Tutorial/Paths#Arcs) - d: `M ${startPoint.x} ${startPoint.y} - A ${this.options.radius} ${this.options.radius} 0 ${largeArcFlag} ${sweepFlag} ${endPoint.x} ${endPoint.y}`, - stroke: this.options.outerStrokeColor, - strokeWidth: this.options.outerStrokeWidth, - strokeLinecap: this.options.outerStrokeLinecap, - fill: 'none' - }, - circle: { - cx: centre.x, - cy: centre.y, - r: this.options.radius - this.options.space - this.options.outerStrokeWidth / 2 - this.options.innerStrokeWidth / 2, - fill: 'none', - stroke: this.options.innerStrokeColor, - strokeWidth: this.options.innerStrokeWidth, - }, - title: title, - units: units, - subtitle: subtitle, - image: { - x: centre.x - this.options.imageWidth / 2, - y: centre.y - this.options.imageHeight / 2, - src: this.options.imageSrc, - width: this.options.imageWidth, - height: this.options.imageHeight, - }, - outerLinearGradient: { - id: 'outer-linear-' + this._gradientUUID, - colorStop1: this.options.outerStrokeColor, - colorStop2: this.options.outerStrokeGradientStopColor === 'transparent' ? '#FFF' : this.options.outerStrokeGradientStopColor, - }, - radialGradient: { - id: 'radial-' + this._gradientUUID, - colorStop1: this.options.backgroundColor, - colorStop2: this.options.backgroundGradientStopColor === 'transparent' ? '#FFF' : this.options.backgroundGradientStopColor, - } - }; - }; - getAnimationParameters = (previousPercent: number, currentPercent: number) => { - const MIN_INTERVAL = 10; - let times: number, step: number, interval: number; - let fromPercent = this.options.startFromZero ? 0 : (previousPercent < 0 ? 0 : previousPercent); - let toPercent = currentPercent < 0 ? 0 : this.min(currentPercent, this.options.maxPercent); - let delta = Math.abs(Math.round(toPercent - fromPercent)); - - if (delta >= 100) { - // we will finish animation in 100 times - times = 100; - if (!this.options.animateTitle && !this.options.animateSubtitle) { - step = 1; - } else { - // show title or subtitle animation even if the arc is full, we also need to finish it in 100 times. - step = Math.round(delta / times); - } + @Output() onClick: EventEmitter = new EventEmitter(); + + @Input() name: string; + @Input() class: string; + @Input() backgroundGradient: boolean; + @Input() backgroundColor: string; + @Input() backgroundGradientStopColor: String; + @Input() backgroundOpacity: number; + @Input() backgroundStroke: string; + @Input() backgroundStrokeWidth: number; + @Input() backgroundPadding: number; + + @Input() radius: number; + @Input() space: number; + @Input() percent: number; + @Input() toFixed: number; + @Input() maxPercent: number; + @Input() renderOnClick: boolean; + + @Input() units: string; + @Input() unitsFontSize: string; + @Input() unitsFontWeight: string; + @Input() unitsColor: string; + + @Input() outerStrokeGradient: boolean; + @Input() outerStrokeWidth: number; + @Input() outerStrokeColor: string; + @Input() outerStrokeGradientStopColor: String; + @Input() outerStrokeLinecap: string; + + @Input() innerStrokeColor: string; + @Input() innerStrokeWidth: string | number; + + @Input() titleFormat: Function; + @Input() title: string | Array; + @Input() titleColor: string; + @Input() titleFontSize: string; + @Input() titleFontWeight: string; + + @Input() subtitleFormat: Function; + @Input() subtitle: string | string[]; + @Input() subtitleColor: string; + @Input() subtitleFontSize: string; + @Input() subtitleFontWeight: string; + + @Input() imageSrc: string; + @Input() imageHeight: number; + @Input() imageWidth: number; + + @Input() animation: boolean; + @Input() animateTitle: boolean; + @Input() animateSubtitle: boolean; + @Input() animationDuration: number; + + @Input() showTitle: boolean; + @Input() showSubtitle: boolean; + @Input() showUnits: boolean; + @Input() showImage: boolean; + @Input() showBackground: boolean; + @Input() showInnerStroke: boolean; + @Input() clockwise: boolean; + @Input() responsive: boolean; + @Input() startFromZero: boolean; + @Input() showZeroOuterStroke: boolean; + + @Input() lazy: boolean; + + @Input('options') templateOptions: CircleProgressOptions; + + // of component + svgElement: HTMLElement = null; + // whether is in viewport + isInViewport: Boolean = false; + // event for notifying viewport change caused by scrolling or resizing + onViewportChanged: EventEmitter<{ oldValue: Boolean; newValue: Boolean }> = new EventEmitter(); + window: Window; + _viewportChangedSubscriber: Subscription = null; + + svg: any; + + options: CircleProgressOptions = new CircleProgressOptions(); + defaultOptions: CircleProgressOptions = new CircleProgressOptions(); + _lastPercent: number = 0; + _gradientUUID: string = null; + render = () => { + this.applyOptions(); + + if (this.options.lazy) { + // Draw svg if it doesn't exist + this.svgElement === null && this.draw(this._lastPercent); + // Draw it only when it's in the viewport + if (this.isInViewport) { + // Draw it at the latest position when I am in. + if (this.options.animation && this.options.animationDuration > 0) { + this.animate(this._lastPercent, this.options.percent); } else { - // we will finish in as many times as the number of percent. - times = delta; - step = 1; - } - // Get the interval of timer - interval = Math.round(this.options.animationDuration / times); - // Readjust all values if the interval of timer is extremely small. - if (interval < MIN_INTERVAL) { - interval = MIN_INTERVAL; - times = this.options.animationDuration / interval; - if (!this.options.animateTitle && !this.options.animateSubtitle && delta > 100) { - step = Math.round(100 / times); - } else { - step = Math.round(delta / times); - } + this.draw(this.options.percent); } - // step must be greater than 0. - if (step < 1) { - step = 1; - } - return { times: times, step: step, interval: interval }; + this._lastPercent = this.options.percent; + } + } else { + if (this.options.animation && this.options.animationDuration > 0) { + this.animate(this._lastPercent, this.options.percent); + } else { + this.draw(this.options.percent); + } + this._lastPercent = this.options.percent; + } + }; + polarToCartesian = (centerX: number, centerY: number, radius: number, angleInDegrees: number) => { + let angleInRadius = (angleInDegrees * Math.PI) / 180; + let x = centerX + Math.sin(angleInRadius) * radius; + let y = centerY - Math.cos(angleInRadius) * radius; + return { x: x, y: y }; + }; + draw = (percent: number) => { + // make percent reasonable + percent = percent === undefined ? this.options.percent : Math.abs(percent); + // circle percent shouldn't be greater than 100%. + let circlePercent = percent > 100 ? 100 : percent; + // determine box size + let boxSize = this.options.radius * 2 + this.options.outerStrokeWidth * 2; + if (this.options.showBackground) { + boxSize += + this.options.backgroundStrokeWidth * 2 + this.max(0, this.options.backgroundPadding * 2); + } + // the centre of the circle + let centre = { x: boxSize / 2, y: boxSize / 2 }; + // the start point of the arc + let startPoint = { x: centre.x, y: centre.y - this.options.radius }; + // get the end point of the arc + let endPoint = this.polarToCartesian( + centre.x, + centre.y, + this.options.radius, + (360 * (this.options.clockwise ? circlePercent : 100 - circlePercent)) / 100, + ); // #################### + // We'll get an end point with the same [x, y] as the start point when percent is 100%, so move x a little bit. + if (circlePercent === 100) { + endPoint.x = endPoint.x + (this.options.clockwise ? -0.01 : +0.01); + } + // largeArcFlag and sweepFlag + let largeArcFlag: any, sweepFlag: any; + if (circlePercent > 50) { + [largeArcFlag, sweepFlag] = this.options.clockwise ? [1, 1] : [1, 0]; + } else { + [largeArcFlag, sweepFlag] = this.options.clockwise ? [0, 1] : [0, 0]; + } + // percent may not equal the actual percent + let titlePercent = this.options.animateTitle ? percent : this.options.percent; + let titleTextPercent = + titlePercent > this.options.maxPercent + ? `${this.options.maxPercent.toFixed(this.options.toFixed)}+` + : titlePercent.toFixed(this.options.toFixed); + let subtitlePercent = this.options.animateSubtitle ? percent : this.options.percent; + // get title object + let title = { + x: centre.x, + y: centre.y, + textAnchor: 'middle', + color: this.options.titleColor, + fontSize: this.options.titleFontSize, + fontWeight: this.options.titleFontWeight, + texts: [], + tspans: [], }; - animate = (previousPercent: number, currentPercent: number) => { - if (this._timerSubscription && !this._timerSubscription.closed) { - this._timerSubscription.unsubscribe(); - } - let fromPercent = this.options.startFromZero ? 0 : previousPercent; - let toPercent = currentPercent; - let { step: step, interval: interval } = this.getAnimationParameters(fromPercent, toPercent); - let count = fromPercent; - if (fromPercent < toPercent) { - this._timerSubscription = timer(0, interval).subscribe(() => { - count += step; - if (count <= toPercent) { - if (!this.options.animateTitle && !this.options.animateSubtitle && count >= 100) { - this.draw(toPercent); - this._timerSubscription.unsubscribe(); - } else { - this.draw(count); - } - } else { - this.draw(toPercent); - this._timerSubscription.unsubscribe(); - } - }); + // from v0.9.9, both title and titleFormat(...) may be an array of string. + if ( + this.options.titleFormat !== undefined && + this.options.titleFormat.constructor.name === 'Function' + ) { + let formatted = this.options.titleFormat(titlePercent); + if (formatted instanceof Array) { + title.texts = [...formatted]; + } else { + title.texts.push(formatted.toString()); + } + } else { + if (this.options.title === 'auto') { + title.texts.push(titleTextPercent); + } else { + if (this.options.title instanceof Array) { + title.texts = [...this.options.title]; } else { - this._timerSubscription = timer(0, interval).subscribe(() => { - count -= step; - if (count >= toPercent) { - if (!this.options.animateTitle && !this.options.animateSubtitle && toPercent >= 100) { - this.draw(toPercent); - this._timerSubscription.unsubscribe(); - } else { - this.draw(count); - } - } else { - this.draw(toPercent); - this._timerSubscription.unsubscribe(); - } - }); - } - }; - emitClickEvent = (event: any) => { - if (this.options.renderOnClick) { - this.animate(0, this.options.percent); - } - this.onClick.emit(event); - }; - private _timerSubscription: Subscription; - private applyOptions = () => { - // the options of may change already - for (let name of Object.keys(this.options)) { - if (this.hasOwnProperty(name) && this[name] !== undefined) { - this.options[name] = this[name]; - } else if (this.templateOptions && this.templateOptions[name] !== undefined) { - this.options[name] = this.templateOptions[name]; - } + title.texts.push(this.options.title.toString()); } - // make sure key options valid - this.options.radius = Math.abs(+this.options.radius); - this.options.space = +this.options.space; - this.options.percent = +this.options.percent > 0 ? +this.options.percent : 0; - this.options.maxPercent = Math.abs(+this.options.maxPercent); - this.options.animationDuration = Math.abs(this.options.animationDuration); - this.options.outerStrokeWidth = Math.abs(+this.options.outerStrokeWidth); - this.options.innerStrokeWidth = Math.abs(+this.options.innerStrokeWidth); - this.options.backgroundPadding = +this.options.backgroundPadding; - }; - private getRelativeY = (rowNum: number, rowCount: number): string => { - // why '-0.18em'? It's a magic number when property 'alignment-baseline' equals 'baseline'. :) - let initialOffset = -0.18, offset = 1; - return (initialOffset + offset * (rowNum - rowCount / 2)).toFixed(2) + 'em'; + } + } + // get subtitle object + let subtitle = { + x: centre.x, + y: centre.y, + textAnchor: 'middle', + color: this.options.subtitleColor, + fontSize: this.options.subtitleFontSize, + fontWeight: this.options.subtitleFontWeight, + texts: [], + tspans: [], }; - - private min = (a: number, b: number) => { - return a < b ? a : b; + // from v0.9.9, both subtitle and subtitleFormat(...) may be an array of string. + if ( + this.options.subtitleFormat !== undefined && + this.options.subtitleFormat.constructor.name === 'Function' + ) { + let formatted = this.options.subtitleFormat(subtitlePercent); + if (formatted instanceof Array) { + subtitle.texts = [...formatted]; + } else { + subtitle.texts.push(formatted.toString()); + } + } else { + if (this.options.subtitle instanceof Array) { + subtitle.texts = [...this.options.subtitle]; + } else { + subtitle.texts.push(this.options.subtitle.toString()); + } + } + // get units object + let units = { + text: `${this.options.units}`, + fontSize: this.options.unitsFontSize, + fontWeight: this.options.unitsFontWeight, + color: this.options.unitsColor, }; - - private max = (a: number, b: number) => { - return a > b ? a : b; + // get total count of text lines to be shown + let rowCount = 0, + rowNum = 1; + this.options.showTitle && (rowCount += title.texts.length); + this.options.showSubtitle && (rowCount += subtitle.texts.length); + // calc dy for each tspan for title + if (this.options.showTitle) { + for (let span of title.texts) { + title.tspans.push({ span: span, dy: this.getRelativeY(rowNum, rowCount) }); + rowNum++; + } + } + // calc dy for each tspan for subtitle + if (this.options.showSubtitle) { + for (let span of subtitle.texts) { + subtitle.tspans.push({ span: span, dy: this.getRelativeY(rowNum, rowCount) }); + rowNum++; + } + } + // create ID for gradient element + if (null === this._gradientUUID) { + this._gradientUUID = this.uuid(); + } + // Bring it all together + this.svg = { + viewBox: `0 0 ${boxSize} ${boxSize}`, + // Set both width and height to '100%' if it's responsive + width: this.options.responsive ? '100%' : boxSize, + height: this.options.responsive ? '100%' : boxSize, + backgroundCircle: { + cx: centre.x, + cy: centre.y, + r: this.options.radius + this.options.outerStrokeWidth / 2 + this.options.backgroundPadding, + fill: this.options.backgroundColor, + fillOpacity: this.options.backgroundOpacity, + stroke: this.options.backgroundStroke, + strokeWidth: this.options.backgroundStrokeWidth, + }, + path: { + // A rx ry x-axis-rotation large-arc-flag sweep-flag x y (https://developer.mozilla.org/en/docs/Web/SVG/Tutorial/Paths#Arcs) + d: `M ${startPoint.x} ${startPoint.y} + A ${this.options.radius} ${this.options.radius} 0 ${largeArcFlag} ${sweepFlag} ${endPoint.x} ${endPoint.y}`, + stroke: this.options.outerStrokeColor, + strokeWidth: this.options.outerStrokeWidth, + strokeLinecap: this.options.outerStrokeLinecap, + fill: 'none', + }, + circle: { + cx: centre.x, + cy: centre.y, + r: + this.options.radius - + this.options.space - + this.options.outerStrokeWidth / 2 - + this.options.innerStrokeWidth / 2, + fill: 'none', + stroke: this.options.innerStrokeColor, + strokeWidth: this.options.innerStrokeWidth, + }, + title: title, + units: units, + subtitle: subtitle, + image: { + x: centre.x - this.options.imageWidth / 2, + y: centre.y - this.options.imageHeight / 2, + src: this.options.imageSrc, + width: this.options.imageWidth, + height: this.options.imageHeight, + }, + outerLinearGradient: { + id: 'outer-linear-' + this._gradientUUID, + colorStop1: this.options.outerStrokeColor, + colorStop2: + this.options.outerStrokeGradientStopColor === 'transparent' + ? '#FFF' + : this.options.outerStrokeGradientStopColor, + }, + radialGradient: { + id: 'radial-' + this._gradientUUID, + colorStop1: this.options.backgroundColor, + colorStop2: + this.options.backgroundGradientStopColor === 'transparent' + ? '#FFF' + : this.options.backgroundGradientStopColor, + }, }; - - private uuid = () => { - // https://www.w3resource.com/javascript-exercises/javascript-math-exercise-23.php - var dt = new Date().getTime(); - var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = (dt + Math.random() * 16) % 16 | 0; - dt = Math.floor(dt / 16); - return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16); - }); - return uuid; + }; + getAnimationParameters = (previousPercent: number, currentPercent: number) => { + const MIN_INTERVAL = 10; + let times: number, step: number, interval: number; + let fromPercent = this.options.startFromZero ? 0 : previousPercent < 0 ? 0 : previousPercent; + let toPercent = currentPercent < 0 ? 0 : this.min(currentPercent, this.options.maxPercent); + let delta = Math.abs(Math.round(toPercent - fromPercent)); + + if (delta >= 100) { + // we will finish animation in 100 times + times = 100; + if (!this.options.animateTitle && !this.options.animateSubtitle) { + step = 1; + } else { + // show title or subtitle animation even if the arc is full, we also need to finish it in 100 times. + step = Math.round(delta / times); + } + } else { + // we will finish in as many times as the number of percent. + times = delta; + step = 1; } - - public isDrawing(): boolean { - return (this._timerSubscription && !this._timerSubscription.closed); + // Get the interval of timer + interval = Math.round(this.options.animationDuration / times); + // Readjust all values if the interval of timer is extremely small. + if (interval < MIN_INTERVAL) { + interval = MIN_INTERVAL; + times = this.options.animationDuration / interval; + if (!this.options.animateTitle && !this.options.animateSubtitle && delta > 100) { + step = Math.round(100 / times); + } else { + step = Math.round(delta / times); + } } - - public findSvgElement = function () { - if (this.svgElement === null) { - let tags = this.elRef.nativeElement.getElementsByTagName('svg'); - if (tags.length > 0) { - this.svgElement = tags[0]; - } - } + // step must be greater than 0. + if (step < 1) { + step = 1; } - - private isElementInViewport(el): Boolean { - // Return false if el has not been created in page. - if (el === null || el === undefined) return false; - // Check if the element is out of view due to a container scrolling - let rect = el.getBoundingClientRect(), parent = el.parentNode, parentRect; - do { - parentRect = parent.getBoundingClientRect(); - if (rect.top >= parentRect.bottom) return false; - if (rect.bottom <= parentRect.top) return false; - if (rect.left >= parentRect.right) return false; - if (rect.right <= parentRect.left) return false; - parent = parent.parentNode; - } while (parent != this.document.body); - // Check its within the document viewport - if (rect.top >= (this.window.innerHeight || this.document.documentElement.clientHeight)) return false; - if (rect.bottom <= 0) return false; - if (rect.left >= (this.window.innerWidth || this.document.documentElement.clientWidth)) return false; - if (rect.right <= 0) return false; - return true; + return { times: times, step: step, interval: interval }; + }; + animate = (previousPercent: number, currentPercent: number) => { + if (this._timerSubscription && !this._timerSubscription.closed) { + this._timerSubscription.unsubscribe(); } - - checkViewport = () => { - this.findSvgElement(); - let previousValue = this.isInViewport; - this.isInViewport = this.isElementInViewport(this.svgElement); - if (previousValue !== this.isInViewport) { - this.onViewportChanged.emit({ oldValue: previousValue, newValue: this.isInViewport }); + let fromPercent = this.options.startFromZero ? 0 : previousPercent; + let toPercent = currentPercent; + let { step: step, interval: interval } = this.getAnimationParameters(fromPercent, toPercent); + let count = fromPercent; + if (fromPercent < toPercent) { + this._timerSubscription = timer(0, interval).subscribe(() => { + count += step; + if (count <= toPercent) { + if (!this.options.animateTitle && !this.options.animateSubtitle && count >= 100) { + this.draw(toPercent); + this._timerSubscription.unsubscribe(); + } else { + this.draw(count); + } + } else { + this.draw(toPercent); + this._timerSubscription.unsubscribe(); } + }); + } else { + this._timerSubscription = timer(0, interval).subscribe(() => { + count -= step; + if (count >= toPercent) { + if (!this.options.animateTitle && !this.options.animateSubtitle && toPercent >= 100) { + this.draw(toPercent); + this._timerSubscription.unsubscribe(); + } else { + this.draw(count); + } + } else { + this.draw(toPercent); + this._timerSubscription.unsubscribe(); + } + }); } - - onScroll = (event: Event) => { - this.checkViewport(); + }; + emitClickEvent = (event: any) => { + if (this.options.renderOnClick) { + this.animate(0, this.options.percent); } - - loadEventsForLazyMode = () => { - if (this.options.lazy) { - this.document.addEventListener('scroll', this.onScroll, true); - this.window.addEventListener('resize', this.onScroll, true); - if (this._viewportChangedSubscriber === null) { - this._viewportChangedSubscriber = this.onViewportChanged.subscribe(({ oldValue, newValue }) => { - newValue ? this.render() : null; - }); - } - // svgElement must be created in DOM before being checked. - // Is there a better way to check the existence of svgElemnt? - let _timer = timer(0, 50).subscribe(() => { - this.svgElement === null ? this.checkViewport() : _timer.unsubscribe(); - }) - } + this.onClick.emit(event); + }; + private _timerSubscription: Subscription; + private applyOptions = () => { + // the options of may change already + for (let name of Object.keys(this.options)) { + if (this.hasOwnProperty(name) && this[name] !== undefined) { + this.options[name] = this[name]; + } else if (this.templateOptions && this.templateOptions[name] !== undefined) { + this.options[name] = this.templateOptions[name]; + } } - - unloadEventsForLazyMode = () => { - // Remove event listeners - this.document.removeEventListener('scroll', this.onScroll, true); - this.window.removeEventListener('resize', this.onScroll, true); - // Unsubscribe onViewportChanged - if (this._viewportChangedSubscriber !== null) { - this._viewportChangedSubscriber.unsubscribe(); - this._viewportChangedSubscriber = null; - } + // make sure key options valid + this.options.radius = Math.abs(+this.options.radius); + this.options.space = +this.options.space; + this.options.percent = +this.options.percent > 0 ? +this.options.percent : 0; + this.options.maxPercent = Math.abs(+this.options.maxPercent); + this.options.animationDuration = Math.abs(this.options.animationDuration); + this.options.outerStrokeWidth = Math.abs(+this.options.outerStrokeWidth); + this.options.innerStrokeWidth = Math.abs(+this.options.innerStrokeWidth); + this.options.backgroundPadding = +this.options.backgroundPadding; + }; + private getRelativeY = (rowNum: number, rowCount: number): string => { + // why '-0.18em'? It's a magic number when property 'alignment-baseline' equals 'baseline'. :) + let initialOffset = -0.18, + offset = 1; + return (initialOffset + offset * (rowNum - rowCount / 2)).toFixed(2) + 'em'; + }; + + private min = (a: number, b: number) => { + return a < b ? a : b; + }; + + private max = (a: number, b: number) => { + return a > b ? a : b; + }; + + private uuid = () => { + // https://www.w3resource.com/javascript-exercises/javascript-math-exercise-23.php + var dt = new Date().getTime(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (dt + Math.random() * 16) % 16 | 0; + dt = Math.floor(dt / 16); + return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); + return uuid; + }; + + public isDrawing(): boolean { + return this._timerSubscription && !this._timerSubscription.closed; + } + + public findSvgElement = function () { + if (this.svgElement === null) { + let tags = this.elRef.nativeElement.getElementsByTagName('svg'); + if (tags.length > 0) { + this.svgElement = tags[0]; + } } - - ngOnInit() { - this.loadEventsForLazyMode(); + }; + + private isElementInViewport(el): Boolean { + // Return false if el has not been created in page. + if (el === null || el === undefined) return false; + // Check if the element is out of view due to a container scrolling + let rect = el.getBoundingClientRect(), + parent = el.parentNode, + parentRect; + do { + parentRect = parent.getBoundingClientRect(); + if (rect.top >= parentRect.bottom) return false; + if (rect.bottom <= parentRect.top) return false; + if (rect.left >= parentRect.right) return false; + if (rect.right <= parentRect.left) return false; + parent = parent.parentNode; + } while (parent != this.document.body); + // Check its within the document viewport + if (rect.top >= (this.window.innerHeight || this.document.documentElement.clientHeight)) + return false; + if (rect.bottom <= 0) return false; + if (rect.left >= (this.window.innerWidth || this.document.documentElement.clientWidth)) + return false; + if (rect.right <= 0) return false; + return true; + } + + checkViewport = () => { + this.findSvgElement(); + let previousValue = this.isInViewport; + this.isInViewport = this.isElementInViewport(this.svgElement); + if (previousValue !== this.isInViewport) { + this.onViewportChanged.emit({ oldValue: previousValue, newValue: this.isInViewport }); } - - ngOnDestroy() { - this.unloadEventsForLazyMode(); + }; + + onScroll = (event: Event) => { + this.checkViewport(); + }; + + loadEventsForLazyMode = () => { + if (this.options.lazy) { + this.document.addEventListener('scroll', this.onScroll, true); + this.window.addEventListener('resize', this.onScroll, true); + if (this._viewportChangedSubscriber === null) { + this._viewportChangedSubscriber = this.onViewportChanged.subscribe( + ({ oldValue, newValue }) => { + newValue ? this.render() : null; + }, + ); + } + // svgElement must be created in DOM before being checked. + // Is there a better way to check the existence of svgElemnt? + let _timer = timer(0, 50).subscribe(() => { + this.svgElement === null ? this.checkViewport() : _timer.unsubscribe(); + }); } + }; + + unloadEventsForLazyMode = () => { + // Remove event listeners + this.document.removeEventListener('scroll', this.onScroll, true); + this.window.removeEventListener('resize', this.onScroll, true); + // Unsubscribe onViewportChanged + if (this._viewportChangedSubscriber !== null) { + this._viewportChangedSubscriber.unsubscribe(); + this._viewportChangedSubscriber = null; + } + }; - ngOnChanges(changes: SimpleChanges) { + ngOnInit() { + this.loadEventsForLazyMode(); + } - this.render(); + ngOnDestroy() { + this.unloadEventsForLazyMode(); + } - if ('lazy' in changes) { - changes.lazy.currentValue ? this.loadEventsForLazyMode() : this.unloadEventsForLazyMode(); - } + ngOnChanges(changes: SimpleChanges) { + this.render(); + if ('lazy' in changes) { + changes.lazy.currentValue ? this.loadEventsForLazyMode() : this.unloadEventsForLazyMode(); } - - constructor(defaultOptions: CircleProgressOptions, private elRef: ElementRef, @Inject(DOCUMENT) private document: any) { - this.document = document; - this.window = this.document.defaultView; - Object.assign(this.options, defaultOptions); - Object.assign(this.defaultOptions, defaultOptions); - } - + } + + constructor( + defaultOptions: CircleProgressOptions, + private elRef: ElementRef, + @Inject(DOCUMENT) private document: any, + ) { + this.document = document; + this.window = this.document.defaultView; + Object.assign(this.options, defaultOptions); + Object.assign(this.defaultOptions, defaultOptions); + } } diff --git a/projects/ng-circle-progress/src/lib/ng-circle-progress.module.ts b/projects/ng-circle-progress/src/lib/ng-circle-progress.module.ts index 279603b..4fe6cff 100644 --- a/projects/ng-circle-progress/src/lib/ng-circle-progress.module.ts +++ b/projects/ng-circle-progress/src/lib/ng-circle-progress.module.ts @@ -1,22 +1,23 @@ import { NgModule, ModuleWithProviders } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { CircleProgressComponent, CircleProgressOptionsInterface, CircleProgressOptions } from './ng-circle-progress.component'; - +import { + CircleProgressComponent, + CircleProgressOptionsInterface, + CircleProgressOptions, +} from './ng-circle-progress.component'; @NgModule({ declarations: [CircleProgressComponent], - imports: [ - CommonModule - ], - exports: [CircleProgressComponent] + imports: [CommonModule], + exports: [CircleProgressComponent], }) export class NgCircleProgressModule { - static forRoot(options: CircleProgressOptionsInterface = {}): ModuleWithProviders { + static forRoot( + options: CircleProgressOptionsInterface = {}, + ): ModuleWithProviders { return { ngModule: NgCircleProgressModule, - providers: [ - { provide: CircleProgressOptions, useValue: options } - ] + providers: [{ provide: CircleProgressOptions, useValue: options }], }; } } diff --git a/projects/ng-circle-progress/tsconfig.lib.json b/projects/ng-circle-progress/tsconfig.lib.json index 6e06ad5..c754a25 100644 --- a/projects/ng-circle-progress/tsconfig.lib.json +++ b/projects/ng-circle-progress/tsconfig.lib.json @@ -8,18 +8,12 @@ "declarationMap": true, "inlineSources": true, "types": [], - "lib": [ - "dom", - "es2018" - ] + "lib": ["dom", "es2018"] }, "angularCompilerOptions": { "skipTemplateCodegen": true, "strictMetadataEmit": true, "enableResourceInlining": true }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/projects/ng-circle-progress/tsconfig.spec.json b/projects/ng-circle-progress/tsconfig.spec.json index 715dd0a..fafd1e1 100644 --- a/projects/ng-circle-progress/tsconfig.spec.json +++ b/projects/ng-circle-progress/tsconfig.spec.json @@ -3,15 +3,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", - "types": [ - "jasmine" - ] + "types": ["jasmine"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/projects/ng-circle-progress/tslint.json b/projects/ng-circle-progress/tslint.json index 124133f..205aeda 100644 --- a/projects/ng-circle-progress/tslint.json +++ b/projects/ng-circle-progress/tslint.json @@ -1,17 +1,7 @@ { "extends": "../../tslint.json", "rules": { - "directive-selector": [ - true, - "attribute", - "lib", - "camelCase" - ], - "component-selector": [ - true, - "element", - "lib", - "kebab-case" - ] + "directive-selector": [true, "attribute", "lib", "camelCase"], + "component-selector": [true, "element", "lib", "kebab-case"] } } diff --git a/src/app/app.component.html b/src/app/app.component.html index b99e256..1405ff9 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,7 +1,7 @@

NgCircleProgress Demo

-
+

A simple circle progress component created for Angular based on SVG Graphics.

View on GitHub
@@ -9,108 +9,244 @@

NgCircleProgress Demo

-
- - - - - - - +
+ + + + + + +
-
-
ng circle progress
- + [outerStrokeGradientStopColor]="options.outerStrokeGradientStopColor" + [lazy]="options.lazy" + >
-
-
+
- - - + + - +
-
@@ -121,15 +257,11 @@

NgCircleProgress Demo

-
{{sourceCode}}
+
{{ sourceCode }}
-
-
-
- -
\ No newline at end of file +
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 1bb032c..5ec4551 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -4,9 +4,7 @@ import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], + declarations: [AppComponent], }).compileComponents(); }); @@ -26,6 +24,8 @@ describe('AppComponent', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement; - expect(compiled.querySelector('.content span').textContent).toContain('ng-circle-progress-library app is running!'); + expect(compiled.querySelector('.content span').textContent).toContain( + 'ng-circle-progress-library app is running!', + ); }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 6b5494d..8046e38 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -4,19 +4,19 @@ import { CircleProgressComponent, CircleProgressOptions } from 'ng-circle-progre @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] + styleUrls: ['./app.component.css'], }) export class AppComponent { - @ViewChild('circleProgress') circleProgress: CircleProgressComponent; - githubLink = "https://github.com/bootsoon/ng-circle-progress"; + githubLink = 'https://github.com/bootsoon/ng-circle-progress'; _timer = null; controlGroups = [ { - groupName: 'Basic', controls: [ + groupName: 'Basic', + controls: [ { name: 'percent', type: 'range', min: 1, max: 1000, step: 0.01 }, { name: 'maxPercent', type: 'range', min: 50, max: 1000, step: 10 }, { name: 'toFixed', type: 'range', min: 0, max: 5, step: 1 }, @@ -30,10 +30,11 @@ export class AppComponent { { name: 'responsive', type: 'checkbox' }, { name: 'startFromZero', type: 'checkbox' }, { name: 'showZeroOuterStroke', type: 'checkbox' }, - ] + ], }, { - groupName: 'Size', controls: [ + groupName: 'Size', + controls: [ { name: 'radius', type: 'range', min: 20, max: 250, step: 1 }, { name: 'backgroundPadding', type: 'range', min: -50, max: 50, step: 1 }, { name: 'imageHeight', type: 'range', min: 20, max: 250, step: 1 }, @@ -41,7 +42,8 @@ export class AppComponent { ], }, { - groupName: 'Color', controls: [ + groupName: 'Color', + controls: [ { name: 'backgroundGradient', type: 'checkbox' }, { name: 'backgroundOpacity', type: 'range', min: 0, max: 1, step: 0.1 }, { name: 'backgroundColor', type: 'color' }, @@ -57,33 +59,40 @@ export class AppComponent { ], }, { - groupName: 'Stroke', controls: [ + groupName: 'Stroke', + controls: [ { name: 'outerStrokeWidth', type: 'range', min: 1, max: 50, step: 1 }, { name: 'space', type: 'range', min: -20, max: 50, step: 1 }, { name: 'innerStrokeWidth', type: 'range', min: 0, max: 50, step: 1 }, { name: 'backgroundStrokeWidth', type: 'range', min: 0, max: 50, step: 1 }, - { name: 'outerStrokeLinecap', type: 'select', options: ['butt', 'round', 'square', 'inherit'] }, + { + name: 'outerStrokeLinecap', + type: 'select', + options: ['butt', 'round', 'square', 'inherit'], + }, ], }, { - groupName: 'Font', controls: [ + groupName: 'Font', + controls: [ { name: 'titleFontSize', type: 'range', min: 10, max: 100, step: 1 }, { name: 'unitsFontSize', type: 'range', min: 10, max: 100, step: 1 }, { name: 'subtitleFontSize', type: 'range', min: 10, max: 100, step: 1 }, { name: 'titleFontWeight', type: 'range', min: 100, max: 900, step: 100 }, { name: 'unitsFontWeight', type: 'range', min: 100, max: 900, step: 100 }, { name: 'subtitleFontWeight', type: 'range', min: 100, max: 900, step: 100 }, - ] + ], }, { - groupName: 'Animation', controls: [ + groupName: 'Animation', + controls: [ { name: 'animation', type: 'checkbox' }, { name: 'animateTitle', type: 'checkbox' }, { name: 'lazy', type: 'checkbox' }, { name: 'animationDuration', type: 'range', min: 0, max: 10000, step: 100 }, - ] + ], }, - ] + ]; options = new CircleProgressOptions(); @@ -98,17 +107,17 @@ export class AppComponent { showSubtitle: false, subtitleFormat: (percent: number): string => { if (percent < 25) { - this.ngCircleOptions.outerStrokeColor = "red"; + this.ngCircleOptions.outerStrokeColor = 'red'; } else if (percent < 50) { - this.ngCircleOptions.outerStrokeColor = "yellow"; + this.ngCircleOptions.outerStrokeColor = 'yellow'; } else if (percent < 75) { - this.ngCircleOptions.outerStrokeColor = "blue"; + this.ngCircleOptions.outerStrokeColor = 'blue'; } else { - this.ngCircleOptions.outerStrokeColor = "green"; + this.ngCircleOptions.outerStrokeColor = 'green'; } return ''; - } - } + }, + }; optionsA = { percent: 85, @@ -116,9 +125,9 @@ export class AppComponent { showBackground: false, outerStrokeWidth: 10, innerStrokeWidth: 5, - subtitleFormat: false, // clear subtitleFormat coming from other options, because Angular does not assign if variable is undefined. + subtitleFormat: false, // clear subtitleFormat coming from other options, because Angular does not assign if variable is undefined. startFromZero: false, - } + }; optionsB = { percent: 50, @@ -136,9 +145,9 @@ export class AppComponent { units: ' Point', unitsColor: '#483500', subtitleColor: '#483500', - subtitleFormat: false, // clear subtitleFormat coming from other options, because Angular does not assign if variable is undefined. + subtitleFormat: false, // clear subtitleFormat coming from other options, because Angular does not assign if variable is undefined. startFromZero: false, - } + }; optionsC = { percent: 99.99, @@ -151,9 +160,9 @@ export class AppComponent { innerStrokeColor: '#32CD32', outerStrokeColor: '#FF6347', toFixed: 2, - subtitleFormat: false, // clear subtitleFormat coming from other options, because Angular does not assign if variable is undefined. + subtitleFormat: false, // clear subtitleFormat coming from other options, because Angular does not assign if variable is undefined. startFromZero: false, - } + }; optionsD = { percent: 101, @@ -172,12 +181,12 @@ export class AppComponent { startFromZero: false, subtitleFormat: (percent: number): string => { if (percent >= 100) { - return "Congratulations!" + return 'Congratulations!'; } else { - return "Progress" + return 'Progress'; } - } - } + }, + }; optionsE = { percent: 75, @@ -185,8 +194,8 @@ export class AppComponent { outerStrokeWidth: 10, innerStrokeWidth: 10, space: -10, - outerStrokeColor: "#4882c2", - innerStrokeColor: "#e7e8ea", + outerStrokeColor: '#4882c2', + innerStrokeColor: '#e7e8ea', showBackground: false, title: 'UI', animateTitle: false, @@ -199,8 +208,8 @@ export class AppComponent { lazy: true, subtitleFormat: (percent: number): string => { return `${percent}%`; - } - } + }, + }; optionsF = { percent: 60, @@ -209,8 +218,8 @@ export class AppComponent { outerStrokeWidth: 2, innerStrokeWidth: 2, space: -2, - outerStrokeColor: "#808080", - innerStrokeColor: "#e7e8ea", + outerStrokeColor: '#808080', + innerStrokeColor: '#e7e8ea', showBackground: true, title: ['working', 'in', 'progress'], titleFontSize: 12, @@ -221,8 +230,8 @@ export class AppComponent { animationDuration: 1000, subtitleFormat: (percent: number): string => { return `${percent}%`; - } - } + }, + }; optionsG = { percent: 75, @@ -230,61 +239,61 @@ export class AppComponent { outerStrokeWidth: 5, innerStrokeWidth: 5, space: -5, - outerStrokeColor: "#76C2AF", - innerStrokeColor: "#ffffff", + outerStrokeColor: '#76C2AF', + innerStrokeColor: '#ffffff', showBackground: false, showImage: true, - imageSrc: "assets/images/music.svg", + imageSrc: 'assets/images/music.svg', imageHeight: 105, imageWidth: 105, - } + }; - onValueChanged = (event) => { + onValueChanged = event => { try { if (event.srcElement.name === 'toFixed') { let toFixed = +event.srcElement.value; this.controlGroups[0].controls[0]['step'] = 1 / Math.pow(10, toFixed); } } catch (e) { - console.error(e) + console.error(e); } - } + }; copyOptions = (event, options) => { this.options = Object.assign({}, this.circleProgress.defaultOptions, options); - } + }; resetOptions = () => { this.stop(); this.options = new CircleProgressOptions(); - } + }; start = () => { if (this._timer !== null) { clearInterval(this._timer); } this._timer = window.setInterval(() => { - this.options.percent = (Math.round(Math.random() * 100)); + this.options.percent = Math.round(Math.random() * 100); }, 1000); - } + }; stop = () => { if (this._timer !== null) { clearInterval(this._timer); this._timer = null; } - } + }; destroyed: Boolean = false; toggleDestroyed = () => { this.destroyed = !this.destroyed; - } + }; getConfiguration = () => { // Didn't find a better way to fix "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked." return {}; - } + }; ngAfterViewInit() { // Didn't find a better way to fix "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked." @@ -299,7 +308,7 @@ export class AppComponent { } return configurations; }; - } + } public get sourceCode() { let json = JSON.stringify(this.getConfiguration(), null, 16).replace(/\n}/g, '}'); @@ -319,6 +328,4 @@ export class AppComponent { `.replace(/\n[ ]{4}/g, '\n'); return code; } - - } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5dd4398..1a75b17 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,19 +4,11 @@ import { FormsModule } from '@angular/forms'; import { NgCircleProgressModule } from 'ng-circle-progress'; import { AppComponent } from './app.component'; - @NgModule({ - declarations: [ - AppComponent - ], - imports: [ - BrowserModule, - FormsModule, - NgCircleProgressModule.forRoot(), - ], - exports: [ - ], + declarations: [AppComponent], + imports: [BrowserModule, FormsModule, NgCircleProgressModule.forRoot()], + exports: [], providers: [], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {}