Local
diff --git a/cypress/fixtures/vdui-components.js b/cypress/fixtures/vdui-components.js
index 890d3f10..44ab63f4 100644
--- a/cypress/fixtures/vdui-components.js
+++ b/cypress/fixtures/vdui-components.js
@@ -1962,7 +1962,7 @@ export const components = [
wrapperClass: ".vue-ui-treemap",
},
{
- name: "VueUiVerticalBar",
+ name: "VueUiHorizontalBar",
dataset: [
{
name: "Serie 1",
@@ -2437,6 +2437,42 @@ export const components = [
},
},
wrapperClass: ".vue-ui-stackbar",
+ },
+ {
+ name: "VueUiStackline",
+ dataset: [
+ {
+ name: "Series 1",
+ series: [10, 20, 30, 10, 20, 4, 5],
+ },
+ {
+ name: "Series 2",
+ series: [20, 40, -60, 20, 10],
+ },
+ {
+ name: "Series 3",
+ series: [20, 40, 60, 20, 10],
+ },
+ ],
+ config: {
+ style: {
+ chart: {
+ grid: {
+ x: {
+ axisName: { text: "x" },
+ },
+ y: {
+ axisName: { text: "y" },
+ },
+ },
+ title: {
+ text: "Title",
+ subtitle: { text: "Subtitle" },
+ },
+ },
+ },
+ },
+ wrapperClass: ".vue-ui-stackline",
},
{
name: "VueUiBullet",
diff --git a/package-lock.json b/package-lock.json
index 666b4b00..6cea53b0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "vue-data-ui",
- "version": "3.4.2",
+ "version": "3.7.7",
"lockfileVersion": 3,
"requires": true,
"dev": true,
@@ -8,17 +8,17 @@
"packages": {
"": {
"name": "vue-data-ui",
- "version": "3.4.2",
+ "version": "3.7.7",
"license": "MIT",
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
- "cypress": "^14.5.0",
+ "cypress": "^15.6.0",
"remove-attr": "^0.0.13",
"sass": "^1.57.1",
"simple-git": "^3.24.0",
- "vite": "^7.1.11",
- "vitest": "^3.2.4",
- "vue": "^3.5.22"
+ "vite": "^7.2.2",
+ "vitest": "^4.0.8",
+ "vue": "^3.5.24"
},
"peerDependencies": {
"jspdf": "^3.0.1",
@@ -41,9 +41,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
- "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -51,13 +51,13 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
- "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
+ "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.28.4"
+ "@babel/types": "^7.28.5"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -67,24 +67,25 @@
}
},
"node_modules/@babel/types": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
- "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.27.1"
+ "@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@cypress/request": {
- "version": "3.0.8",
- "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.8.tgz",
- "integrity": "sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.9.tgz",
+ "integrity": "sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@@ -92,7 +93,7 @@
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
- "form-data": "~4.0.0",
+ "form-data": "~4.0.4",
"http-signature": "~1.4.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
@@ -1133,20 +1134,30 @@
"win32"
]
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/chai": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
- "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+ "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@types/deep-eql": "*"
+ "@types/deep-eql": "*",
+ "assertion-error": "^2.0.1"
}
},
"node_modules/@types/deep-eql": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.8",
@@ -1177,6 +1188,13 @@
"integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==",
"dev": true
},
+ "node_modules/@types/tmp": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz",
+ "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/yauzl": {
"version": "2.10.3",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
@@ -1205,37 +1223,40 @@
}
},
"node_modules/@vitest/expect": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
- "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.8.tgz",
+ "integrity": "sha512-Rv0eabdP/xjAHQGr8cjBm+NnLHNoL268lMDK85w2aAGLFoVKLd8QGnVon5lLtkXQCoYaNL0wg04EGnyKkkKhPA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
+ "@standard-schema/spec": "^1.0.0",
"@types/chai": "^5.2.2",
- "@vitest/spy": "3.2.4",
- "@vitest/utils": "3.2.4",
- "chai": "^5.2.0",
- "tinyrainbow": "^2.0.0"
+ "@vitest/spy": "4.0.8",
+ "@vitest/utils": "4.0.8",
+ "chai": "^6.2.0",
+ "tinyrainbow": "^3.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/mocker": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
- "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.8.tgz",
+ "integrity": "sha512-9FRM3MZCedXH3+pIh+ME5Up2NBBHDq0wqwhOKkN4VnvCiKbVxddqH9mSGPZeawjd12pCOGnl+lo/ZGHt0/dQSg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/spy": "3.2.4",
+ "@vitest/spy": "4.0.8",
"estree-walker": "^3.0.3",
- "magic-string": "^0.30.17"
+ "magic-string": "^0.30.21"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"msw": "^2.4.9",
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ "vite": "^6.0.0 || ^7.0.0-0"
},
"peerDependenciesMeta": {
"msw": {
@@ -1246,49 +1267,42 @@
}
}
},
- "node_modules/@vitest/mocker/node_modules/estree-walker": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
- "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
- "dev": true,
- "dependencies": {
- "@types/estree": "^1.0.0"
- }
- },
"node_modules/@vitest/pretty-format": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
- "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.8.tgz",
+ "integrity": "sha512-qRrjdRkINi9DaZHAimV+8ia9Gq6LeGz2CgIEmMLz3sBDYV53EsnLZbJMR1q84z1HZCMsf7s0orDgZn7ScXsZKg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "tinyrainbow": "^2.0.0"
+ "tinyrainbow": "^3.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/runner": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
- "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.8.tgz",
+ "integrity": "sha512-mdY8Sf1gsM8hKJUQfiPT3pn1n8RF4QBcJYFslgWh41JTfrK1cbqY8whpGCFzBl45LN028g0njLCYm0d7XxSaQQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/utils": "3.2.4",
- "pathe": "^2.0.3",
- "strip-literal": "^3.0.0"
+ "@vitest/utils": "4.0.8",
+ "pathe": "^2.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/snapshot": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
- "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.8.tgz",
+ "integrity": "sha512-Nar9OTU03KGiubrIOFhcfHg8FYaRaNT+bh5VUlNz8stFhCZPNrJvmZkhsr1jtaYvuefYFwK2Hwrq026u4uPWCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.2.4",
- "magic-string": "^0.30.17",
+ "@vitest/pretty-format": "4.0.8",
+ "magic-string": "^0.30.21",
"pathe": "^2.0.3"
},
"funding": {
@@ -1296,137 +1310,149 @@
}
},
"node_modules/@vitest/spy": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
- "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.8.tgz",
+ "integrity": "sha512-nvGVqUunyCgZH7kmo+Ord4WgZ7lN0sOULYXUOYuHr55dvg9YvMz3izfB189Pgp28w0vWFbEEfNc/c3VTrqrXeA==",
"dev": true,
- "dependencies": {
- "tinyspy": "^4.0.3"
- },
+ "license": "MIT",
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/utils": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
- "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.8.tgz",
+ "integrity": "sha512-pdk2phO5NDvEFfUTxcTP8RFYjVj/kfLSPIN5ebP2Mu9kcIMeAQTbknqcFEyBcC4z2pJlJI9aS5UQjcYfhmKAow==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.2.4",
- "loupe": "^3.1.4",
- "tinyrainbow": "^2.0.0"
+ "@vitest/pretty-format": "4.0.8",
+ "tinyrainbow": "^3.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vue/compiler-core": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz",
- "integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.24.tgz",
+ "integrity": "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.4",
- "@vue/shared": "3.5.22",
+ "@babel/parser": "^7.28.5",
+ "@vue/shared": "3.5.24",
"entities": "^4.5.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
+ "node_modules/@vue/compiler-core/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@vue/compiler-dom": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz",
- "integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.24.tgz",
+ "integrity": "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/compiler-core": "3.5.22",
- "@vue/shared": "3.5.22"
+ "@vue/compiler-core": "3.5.24",
+ "@vue/shared": "3.5.24"
}
},
"node_modules/@vue/compiler-sfc": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.22.tgz",
- "integrity": "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.24.tgz",
+ "integrity": "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.4",
- "@vue/compiler-core": "3.5.22",
- "@vue/compiler-dom": "3.5.22",
- "@vue/compiler-ssr": "3.5.22",
- "@vue/shared": "3.5.22",
+ "@babel/parser": "^7.28.5",
+ "@vue/compiler-core": "3.5.24",
+ "@vue/compiler-dom": "3.5.24",
+ "@vue/compiler-ssr": "3.5.24",
+ "@vue/shared": "3.5.24",
"estree-walker": "^2.0.2",
- "magic-string": "^0.30.19",
+ "magic-string": "^0.30.21",
"postcss": "^8.5.6",
"source-map-js": "^1.2.1"
}
},
+ "node_modules/@vue/compiler-sfc/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@vue/compiler-ssr": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.22.tgz",
- "integrity": "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.24.tgz",
+ "integrity": "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/compiler-dom": "3.5.22",
- "@vue/shared": "3.5.22"
+ "@vue/compiler-dom": "3.5.24",
+ "@vue/shared": "3.5.24"
}
},
"node_modules/@vue/reactivity": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz",
- "integrity": "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.24.tgz",
+ "integrity": "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/shared": "3.5.22"
+ "@vue/shared": "3.5.24"
}
},
"node_modules/@vue/runtime-core": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.22.tgz",
- "integrity": "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.24.tgz",
+ "integrity": "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/reactivity": "3.5.22",
- "@vue/shared": "3.5.22"
+ "@vue/reactivity": "3.5.24",
+ "@vue/shared": "3.5.24"
}
},
"node_modules/@vue/runtime-dom": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.22.tgz",
- "integrity": "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.24.tgz",
+ "integrity": "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/reactivity": "3.5.22",
- "@vue/runtime-core": "3.5.22",
- "@vue/shared": "3.5.22",
+ "@vue/reactivity": "3.5.24",
+ "@vue/runtime-core": "3.5.24",
+ "@vue/shared": "3.5.24",
"csstype": "^3.1.3"
}
},
"node_modules/@vue/server-renderer": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.22.tgz",
- "integrity": "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.24.tgz",
+ "integrity": "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/compiler-ssr": "3.5.22",
- "@vue/shared": "3.5.22"
+ "@vue/compiler-ssr": "3.5.24",
+ "@vue/shared": "3.5.24"
},
"peerDependencies": {
- "vue": "3.5.22"
+ "vue": "3.5.24"
}
},
"node_modules/@vue/shared": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz",
- "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.24.tgz",
+ "integrity": "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==",
"dev": true,
"license": "MIT"
},
@@ -1516,6 +1542,7 @@
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"safer-buffer": "~2.1.0"
}
@@ -1525,6 +1552,7 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.8"
}
@@ -1534,6 +1562,7 @@
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
}
@@ -1547,17 +1576,12 @@
"node": ">=8"
}
},
- "node_modules/async": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
- "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
- "dev": true
- },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/at-least-node": {
"version": "1.0.0",
@@ -1573,6 +1597,7 @@
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "*"
}
@@ -1581,7 +1606,8 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
"integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/base64-js": {
"version": "1.5.1",
@@ -1608,6 +1634,7 @@
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"tweetnacl": "^0.14.3"
}
@@ -1670,15 +1697,6 @@
"node": "*"
}
},
- "node_modules/cac": {
- "version": "6.7.14",
- "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
- "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/cachedir": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz",
@@ -1693,6 +1711,7 @@
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
@@ -1706,6 +1725,7 @@
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
@@ -1721,22 +1741,17 @@
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
- "dev": true
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/chai": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
- "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.0.tgz",
+ "integrity": "sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==",
"dev": true,
- "dependencies": {
- "assertion-error": "^2.0.1",
- "check-error": "^2.1.1",
- "deep-eql": "^5.0.1",
- "loupe": "^3.1.0",
- "pathval": "^2.0.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/chalk": {
@@ -1767,24 +1782,6 @@
"node": ">=8"
}
},
- "node_modules/check-error": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
- "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
- "dev": true,
- "engines": {
- "node": ">= 16"
- }
- },
- "node_modules/check-more-types": {
- "version": "2.24.0",
- "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
- "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -1906,6 +1903,7 @@
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
@@ -1935,7 +1933,8 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
@@ -1959,23 +1958,24 @@
"license": "MIT"
},
"node_modules/cypress": {
- "version": "14.5.0",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-14.5.0.tgz",
- "integrity": "sha512-1HOnKvWep0LkWuFwPeWkZ0TDl7ivi2/Mz+WNU4dfkeLJaFndS3Ow6TXT7YjuTqLFI2peJKzPKljVUFdymI2K5g==",
+ "version": "15.6.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.6.0.tgz",
+ "integrity": "sha512-Vqo66GG1vpxZ7H1oDX9umfmzA3nF7Wy80QAc3VjwPREO5zTY4d1xfQFNPpOWleQl9vpdmR2z1liliOcYlRX6rQ==",
"dev": true,
"hasInstallScript": true,
+ "license": "MIT",
"dependencies": {
- "@cypress/request": "^3.0.8",
+ "@cypress/request": "^3.0.9",
"@cypress/xvfb": "^1.2.4",
"@types/sinonjs__fake-timers": "8.1.1",
"@types/sizzle": "^2.3.2",
+ "@types/tmp": "^0.2.3",
"arch": "^2.2.0",
"blob-util": "^2.0.2",
"bluebird": "^3.7.2",
"buffer": "^5.7.1",
"cachedir": "^2.3.0",
"chalk": "^4.1.0",
- "check-more-types": "^2.24.0",
"ci-info": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-table3": "0.6.1",
@@ -1990,10 +1990,8 @@
"extract-zip": "2.0.1",
"figures": "^3.2.0",
"fs-extra": "^9.1.0",
- "getos": "^3.2.1",
"hasha": "5.2.2",
"is-installed-globally": "~0.4.0",
- "lazy-ass": "^1.6.0",
"listr2": "^3.8.3",
"lodash": "^4.17.21",
"log-symbols": "^4.0.0",
@@ -2005,7 +2003,8 @@
"request-progress": "^3.0.0",
"semver": "^7.7.1",
"supports-color": "^8.1.1",
- "tmp": "~0.2.3",
+ "systeminformation": "5.27.7",
+ "tmp": "~0.2.4",
"tree-kill": "1.2.2",
"untildify": "^4.0.0",
"yauzl": "^2.10.0"
@@ -2014,7 +2013,7 @@
"cypress": "bin/cypress"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ "node": "^20.1.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/dashdash": {
@@ -2022,6 +2021,7 @@
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"assert-plus": "^1.0.0"
},
@@ -2036,10 +2036,11 @@
"dev": true
},
"node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
@@ -2052,20 +2053,12 @@
}
}
},
- "node_modules/deep-eql": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
- "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.4.0"
}
@@ -2088,6 +2081,7 @@
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
@@ -2102,6 +2096,7 @@
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
@@ -2153,6 +2148,7 @@
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -2162,6 +2158,7 @@
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -2170,13 +2167,15 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
@@ -2189,6 +2188,7 @@
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
@@ -2249,11 +2249,14 @@
}
},
"node_modules/estree-walker": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
- "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
},
"node_modules/eventemitter2": {
"version": "6.4.7",
@@ -2297,10 +2300,11 @@
}
},
"node_modules/expect-type": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
- "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
+ "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=12.0.0"
}
@@ -2309,7 +2313,8 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/extract-zip": {
"version": "2.0.1",
@@ -2338,7 +2343,8 @@
"dev": true,
"engines": [
"node >=0.6.0"
- ]
+ ],
+ "license": "MIT"
},
"node_modules/fd-slicer": {
"version": "1.1.0",
@@ -2382,6 +2388,7 @@
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "*"
}
@@ -2438,6 +2445,7 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
+ "license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -2447,6 +2455,7 @@
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
@@ -2471,6 +2480,7 @@
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
@@ -2494,20 +2504,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/getos": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
- "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
- "dev": true,
- "dependencies": {
- "async": "^3.2.0"
- }
- },
"node_modules/getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"assert-plus": "^1.0.0"
}
@@ -2532,6 +2534,7 @@
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -2559,6 +2562,7 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -2571,6 +2575,7 @@
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
@@ -2611,6 +2616,7 @@
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -2623,6 +2629,7 @@
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz",
"integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"assert-plus": "^1.0.0",
"jsprim": "^2.0.2",
@@ -2768,7 +2775,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/is-unicode-supported": {
"version": "0.1.0",
@@ -2792,31 +2800,29 @@
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
- "dev": true
- },
- "node_modules/js-tokens": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
- "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
- "dev": true
+ "dev": true,
+ "license": "(AFL-2.1 OR BSD-3-Clause)"
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/jsonfile": {
"version": "6.1.0",
@@ -2838,6 +2844,7 @@
"engines": [
"node >=0.6.0"
],
+ "license": "MIT",
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
@@ -2845,15 +2852,6 @@
"verror": "1.10.0"
}
},
- "node_modules/lazy-ass": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
- "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
- "dev": true,
- "engines": {
- "node": "> 0.8"
- }
- },
"node_modules/listr2": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
@@ -2958,16 +2956,10 @@
"node": ">=8"
}
},
- "node_modules/loupe": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz",
- "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==",
- "dev": true
- },
"node_modules/magic-string": {
- "version": "0.30.19",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
- "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2979,6 +2971,7 @@
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -3008,6 +3001,7 @@
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -3017,6 +3011,7 @@
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
@@ -3090,6 +3085,7 @@
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -3155,16 +3151,8 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
- "dev": true
- },
- "node_modules/pathval": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
- "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
"dev": true,
- "engines": {
- "node": ">= 14.16"
- }
+ "license": "MIT"
},
"node_modules/pend": {
"version": "1.2.0",
@@ -3176,7 +3164,8 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
@@ -3276,6 +3265,7 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
@@ -3400,13 +3390,15 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/sass": {
"version": "1.89.1",
@@ -3466,6 +3458,7 @@
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
@@ -3485,6 +3478,7 @@
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
@@ -3501,6 +3495,7 @@
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -3519,6 +3514,7 @@
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -3588,6 +3584,7 @@
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
"integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
@@ -3615,10 +3612,11 @@
"dev": true
},
"node_modules/std-env": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
- "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
- "dev": true
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/string-width": {
"version": "4.2.3",
@@ -3655,18 +3653,6 @@
"node": ">=6"
}
},
- "node_modules/strip-literal": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
- "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
- "dev": true,
- "dependencies": {
- "js-tokens": "^9.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
"node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -3682,6 +3668,33 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "node_modules/systeminformation": {
+ "version": "5.27.7",
+ "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.27.7.tgz",
+ "integrity": "sha512-saaqOoVEEFaux4v0K8Q7caiauRwjXC4XbD2eH60dxHXbpKxQ8kH9Rf7Jh+nryKpOUSEFxtCdBlSUx0/lO6rwRg==",
+ "dev": true,
+ "license": "MIT",
+ "os": [
+ "darwin",
+ "linux",
+ "win32",
+ "freebsd",
+ "openbsd",
+ "netbsd",
+ "sunos",
+ "android"
+ ],
+ "bin": {
+ "systeminformation": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ },
+ "funding": {
+ "type": "Buy me a coffee",
+ "url": "https://www.buymeacoffee.com/systeminfo"
+ }
+ },
"node_modules/throttleit": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz",
@@ -3757,29 +3770,12 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/tinypool": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
- "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
- "dev": true,
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- }
- },
"node_modules/tinyrainbow": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
- "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
- "dev": true,
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/tinyspy": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz",
- "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz",
+ "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=14.0.0"
}
@@ -3789,6 +3785,7 @@
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz",
"integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"tldts-core": "^6.1.86"
},
@@ -3800,7 +3797,8 @@
"version": "6.1.86",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz",
"integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/tmp": {
"version": "0.2.4",
@@ -3830,6 +3828,7 @@
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz",
"integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"tldts": "^6.1.32"
},
@@ -3857,6 +3856,7 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
},
@@ -3868,7 +3868,8 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
- "dev": true
+ "dev": true,
+ "license": "Unlicense"
},
"node_modules/type-fest": {
"version": "0.21.3",
@@ -3912,6 +3913,7 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
+ "license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
@@ -3924,6 +3926,7 @@
"engines": [
"node >=0.6.0"
],
+ "license": "MIT",
"dependencies": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
@@ -3931,9 +3934,9 @@
}
},
"node_modules/vite": {
- "version": "7.1.11",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz",
- "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==",
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz",
+ "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4005,28 +4008,6 @@
}
}
},
- "node_modules/vite-node": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
- "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
- "dev": true,
- "dependencies": {
- "cac": "^6.7.14",
- "debug": "^4.4.1",
- "es-module-lexer": "^1.7.0",
- "pathe": "^2.0.3",
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
- },
- "bin": {
- "vite-node": "vite-node.mjs"
- },
- "engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
"node_modules/vite/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -4059,40 +4040,38 @@
}
},
"node_modules/vitest": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
- "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.8.tgz",
+ "integrity": "sha512-urzu3NCEV0Qa0Y2PwvBtRgmNtxhj5t5ULw7cuKhIHh3OrkKTLlut0lnBOv9qe5OvbkMH2g38G7KPDCTpIytBVg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@types/chai": "^5.2.2",
- "@vitest/expect": "3.2.4",
- "@vitest/mocker": "3.2.4",
- "@vitest/pretty-format": "^3.2.4",
- "@vitest/runner": "3.2.4",
- "@vitest/snapshot": "3.2.4",
- "@vitest/spy": "3.2.4",
- "@vitest/utils": "3.2.4",
- "chai": "^5.2.0",
- "debug": "^4.4.1",
- "expect-type": "^1.2.1",
- "magic-string": "^0.30.17",
+ "@vitest/expect": "4.0.8",
+ "@vitest/mocker": "4.0.8",
+ "@vitest/pretty-format": "4.0.8",
+ "@vitest/runner": "4.0.8",
+ "@vitest/snapshot": "4.0.8",
+ "@vitest/spy": "4.0.8",
+ "@vitest/utils": "4.0.8",
+ "debug": "^4.4.3",
+ "es-module-lexer": "^1.7.0",
+ "expect-type": "^1.2.2",
+ "magic-string": "^0.30.21",
"pathe": "^2.0.3",
- "picomatch": "^4.0.2",
- "std-env": "^3.9.0",
+ "picomatch": "^4.0.3",
+ "std-env": "^3.10.0",
"tinybench": "^2.9.0",
"tinyexec": "^0.3.2",
- "tinyglobby": "^0.2.14",
- "tinypool": "^1.1.1",
- "tinyrainbow": "^2.0.0",
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
- "vite-node": "3.2.4",
+ "tinyglobby": "^0.2.15",
+ "tinyrainbow": "^3.0.3",
+ "vite": "^6.0.0 || ^7.0.0",
"why-is-node-running": "^2.3.0"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
@@ -4100,9 +4079,11 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/debug": "^4.1.12",
- "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
- "@vitest/browser": "3.2.4",
- "@vitest/ui": "3.2.4",
+ "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
+ "@vitest/browser-playwright": "4.0.8",
+ "@vitest/browser-preview": "4.0.8",
+ "@vitest/browser-webdriverio": "4.0.8",
+ "@vitest/ui": "4.0.8",
"happy-dom": "*",
"jsdom": "*"
},
@@ -4116,7 +4097,13 @@
"@types/node": {
"optional": true
},
- "@vitest/browser": {
+ "@vitest/browser-playwright": {
+ "optional": true
+ },
+ "@vitest/browser-preview": {
+ "optional": true
+ },
+ "@vitest/browser-webdriverio": {
"optional": true
},
"@vitest/ui": {
@@ -4131,10 +4118,11 @@
}
},
"node_modules/vitest/node_modules/picomatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
- "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -4143,17 +4131,17 @@
}
},
"node_modules/vue": {
- "version": "3.5.22",
- "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
- "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
+ "version": "3.5.24",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.24.tgz",
+ "integrity": "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vue/compiler-dom": "3.5.22",
- "@vue/compiler-sfc": "3.5.22",
- "@vue/runtime-dom": "3.5.22",
- "@vue/server-renderer": "3.5.22",
- "@vue/shared": "3.5.22"
+ "@vue/compiler-dom": "3.5.24",
+ "@vue/compiler-sfc": "3.5.24",
+ "@vue/runtime-dom": "3.5.24",
+ "@vue/server-renderer": "3.5.24",
+ "@vue/shared": "3.5.24"
},
"peerDependencies": {
"typescript": "*"
diff --git a/package.json b/package.json
index 6c664b4a..f773ef5a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "vue-data-ui",
"private": false,
- "version": "3.4.2",
+ "version": "3.7.7",
"type": "module",
"description": "A user-empowering data visualization Vue 3 components library for eloquent data storytelling",
"keywords": [
@@ -106,12 +106,12 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
- "cypress": "^14.5.0",
+ "cypress": "^15.6.0",
"remove-attr": "^0.0.13",
"sass": "^1.57.1",
"simple-git": "^3.24.0",
- "vite": "^7.1.11",
- "vitest": "^3.2.4",
- "vue": "^3.5.22"
+ "vite": "^7.2.2",
+ "vitest": "^4.0.8",
+ "vue": "^3.5.24"
}
}
diff --git a/src/App.vue b/src/App.vue
index ce629d5a..81f2c7c1 100755
--- a/src/App.vue
+++ b/src/App.vue
@@ -12,7 +12,7 @@ import ArenaVueUiWheel from "../TestingArena/ArenaVueUiWheel.vue";
import ArenaVueUiTiremarks from "../TestingArena/ArenaVueUiTiremarks.vue";
import ArenaVueUiChestnut from "../TestingArena/ArenaVueUiChestnut.vue";
import ArenaVueUiOnion from "../TestingArena/ArenaVueUiOnion.vue";
-import ArenaVueUiVerticalBar from "../TestingArena/ArenaVueUiVerticalBar.vue";
+import ArenaVueUiHorizontalBar from "../TestingArena/ArenaVueUiHorizontalBar.vue";
import ArenaVueUiHeatmap from "../TestingArena/ArenaVueUiHeatmap.vue";
import ArenaVueUiScatter from "../TestingArena/ArenaVueUiScatter.vue";
import ArenaVueUiCandlestick from "../TestingArena/ArenaVueUiCandlestick.vue";
@@ -59,7 +59,7 @@ import ArenaVueUiRidgeline from "../TestingArena/ArenaVueUiRidgeline.vue";
import ArenaVueUiChord from "../TestingArena/ArenaVueUiChord.vue"
import ArenaVueUiDashboard from "../TestingArena/ArenaVueUiDashboard.vue";
import ArenaVueUiAnnotator from "../TestingArena/ArenaVueUiAnnotator.vue";
-
+import ArenaVueUiStackline from "../TestingArena/ArenaVueUiStackline.vue";
/**
* TODO: migrate manual testing for the following:
@@ -68,6 +68,7 @@ import ArenaVueUiAnnotator from "../TestingArena/ArenaVueUiAnnotator.vue";
*/
const mapping = ref({
+ VueUiStackline: markRaw(ArenaVueUiStackline),
VueUiXy: markRaw(ArenaVueUiXy),
VueUiDonut: markRaw(ArenaVueUiDonut),
VueUiTreemap: markRaw(ArenaVueUiTreemap),
@@ -79,7 +80,7 @@ const mapping = ref({
VueUiTiremarks: markRaw(ArenaVueUiTiremarks),
VueUiChestnut: markRaw(ArenaVueUiChestnut),
VueUiOnion: markRaw(ArenaVueUiOnion),
- VueUiVerticalBar: markRaw(ArenaVueUiVerticalBar),
+ VueUiHorizontalBar: markRaw(ArenaVueUiHorizontalBar),
VueUiHeatmap: markRaw(ArenaVueUiHeatmap),
VueUiScatter: markRaw(ArenaVueUiScatter),
VueUiCandlestick: markRaw(ArenaVueUiCandlestick),
@@ -129,7 +130,7 @@ const mapping = ref({
})
const options = computed(() => Object.keys(mapping.value));
-const selectedComponent = ref('VueUiXyCanvas');
+const selectedComponent = ref('VueUiHorizontalBar');
/**
* Legacy testing arena where some non chart components can be tested
diff --git a/src/TestingArena.vue b/src/TestingArena.vue
index 3327f6dc..b9d06e1c 100644
--- a/src/TestingArena.vue
+++ b/src/TestingArena.vue
@@ -22,7 +22,7 @@ import QuadrantTest from "./components/vue-ui-quadrant.vue";
import GaugeTest from "./components/vue-ui-gauge.vue";
import ChestnutTest from "./components/vue-ui-chestnut.vue";
import OnionTest from "./components/vue-ui-onion.vue";
-import VerticalTest from "./components/vue-ui-vertical-bar.vue";
+import HorizontalTest from "./components/vue-ui-horizontal-bar.vue";
import RatingTest from "./components/vue-ui-rating.vue";
import SkeletonTest from "./components/vue-ui-skeleton.vue";
import SparklineTest from "./components/vue-ui-sparkline.vue";
diff --git a/src/atoms/BaseIcon.vue b/src/atoms/BaseIcon.vue
index 0272504c..523f8d63 100755
--- a/src/atoms/BaseIcon.vue
+++ b/src/atoms/BaseIcon.vue
@@ -32,8 +32,8 @@ const viewBox = computed(() => {
const icons = computed(() => {
return {
- annotator: `
`,
- annotatorDisabled: `
`,
+ annotator: `
`,
+ annotatorDisabled: `
`,
chart3dBar: `
`,
chartAgePyramid: `
`,
chartBar: `
`,
@@ -203,7 +203,8 @@ const icons = computed(() => {
bringToBack: `
`,
printer: `
`,
save: `
`,
- svg: `
`
+ svg: `
`,
+ chartStackline: `
`
}
});
diff --git a/src/atoms/ColorPicker.vue b/src/atoms/ColorPicker.vue
index 7198df10..4c3a4df6 100644
--- a/src/atoms/ColorPicker.vue
+++ b/src/atoms/ColorPicker.vue
@@ -166,7 +166,9 @@ const palette = ref([
:style="colorPickerStyle"
type="button"
>
-
+
+
+
', () => {
@@ -53,6 +53,7 @@ describe('
', () => {
components: { Legend },
setup() {
const legendSet = legend
+ const leg = ref(null);
const config = reactive({
backgroundColor: '#fff',
@@ -62,10 +63,10 @@ describe('
', () => {
cy: 'legend-container'
});
- return { legendSet, config };
+ return { legendSet, config, leg };
},
template: `
-
+
Legend Title
@@ -74,13 +75,53 @@ describe(' ', () => {
`
- }));
-
- cy.get('[data-cy="legend-title"]').should('exist').and('contain', 'Legend Title');
- cy.get('[data-cy="legend-item"]').as('items').should('have.length', 7);
- cy.get('@items').each((item, i) => {
- cy.wrap(item).as('item')
- cy.get('@item').should('contain', `${legend[i].name} - value:${legend[i].value}`)
+ })).then(({ wrapper }) => {
+ cy.get('[data-cy="legend-title"]').should('exist').and('contain', 'Legend Title');
+ cy.get('[data-cy="legend-item"]').as('items').should('have.length', 7);
+ cy.get('@items').each((item, i) => {
+ cy.wrap(item).as('item')
+ cy.get('@item').should('contain', `${legend[i].name} - value:${legend[i].value}`)
+ })
})
});
-});
+
+ it('emits clickMarker with correct payload', () => {
+ const config = {
+ backgroundColor: '#fff',
+ fontSize: 14,
+ color: '#333',
+ paddingBottom: 12,
+ cy: 'legend-container',
+ };
+
+ const handlers = { onMarker: () => {} };
+ cy.spy(handlers, 'onMarker').as('onMarker');
+
+ cy.mount(Legend, {
+ props: {
+ legendSet: legend,
+ config,
+ onClickMarker: handlers.onMarker,
+ },
+ slots: {
+ legendTitle: () =>
+ h('div', {
+ 'data-cy': 'legend-title',
+ style: 'width:100%;text-align:center;font-weight:bold;padding:1rem',
+ }, 'Legend Title'),
+ item: ({ legend: item }) =>
+ h('div', { 'data-cy': 'legend-item' }, `${item.name} - value:${item.value}`),
+ },
+ });
+
+ cy.get('[data-cy="legend-marker"]').should('have.length', legend.length);
+ cy.get('[data-cy="legend-marker"]').first().click();
+
+ cy.get('@onMarker').should('have.been.calledOnce');
+ cy.get('@onMarker').its('firstCall.args.0').then((payload) => {
+ expect(payload).to.have.property('i', 0);
+ expect(payload.legend).to.include(legend[0]);
+ });
+ });
+
+});
\ No newline at end of file
diff --git a/src/atoms/Legend.vue b/src/atoms/Legend.vue
index b479a570..f6fe07fc 100644
--- a/src/atoms/Legend.vue
+++ b/src/atoms/Legend.vue
@@ -44,7 +44,8 @@ function handleClick(legend, i) {
-
{
backgroundColor: backgroundColor,
border: `1px solid ${buttonBorderColor}`
}">
-
+
+
+
+
-
+
+
+
+
+
+
{
backgroundColor: backgroundColor,
border: `1px solid ${buttonBorderColor}`,
}"
- >
-
+ >
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+ }"
+ >
+
+
+
{
return base;
});
+
+defineExpose({
+ placeTooltip
+});
+
diff --git a/src/atoms/UserOptions.cy.js b/src/atoms/UserOptions.cy.js
index 9bbc9654..5a3fb890 100644
--- a/src/atoms/UserOptions.cy.js
+++ b/src/atoms/UserOptions.cy.js
@@ -14,7 +14,8 @@ describe(' ', () => {
hasSort: true,
hasFullscreen: true,
hasAnimation: true,
- hasAnnotator: true
+ hasAnnotator: true,
+ hasSvg: true
}
});
}
@@ -55,7 +56,8 @@ describe(' ', () => {
'user-options-sort',
'user-options-fullscreen',
'user-options-anim',
- 'user-options-annotator'
+ 'user-options-annotator',
+ 'user-options-svg'
].forEach(btn => {
cy.get(`[data-cy="${btn}"]`).should('exist').and('be.visible');
})
@@ -74,6 +76,7 @@ describe(' ', () => {
hasAnimation: true,
hasAnnotator: true,
hasFullscreen: true,
+ hasSvg: true,
chartElement: {
requestFullscreen: () => {},
exitFullscreen: () => {}
@@ -116,6 +119,9 @@ describe(' ', () => {
cy.get('[data-cy="user-options-annotator"]').click().then(() => {
expect(wrapper.emitted('toggleAnnotator')).to.exist
})
+ cy.get('[data-cy="user-options-svg"]').click().then(() => {
+ expect(wrapper.emitted('generateSvg')).to.exist
+ })
})
})
@@ -133,6 +139,7 @@ describe(' ', () => {
hasAnimation: true,
hasAnnotator: true,
hasFullscreen: true,
+ hasSvg: true,
titles: {
open: 'open',
close: 'close',
@@ -146,7 +153,8 @@ describe(' ', () => {
stack: 'stack',
fullscreen: 'fullscreen',
animation: 'animation',
- annotator: 'annotator'
+ annotator: 'annotator',
+ svg: 'svg'
}
}
}).then(() => {
@@ -195,6 +203,10 @@ describe(' ', () => {
cy.get('[data-cy="uo-tooltip"]').should('be.visible').and('contain', 'annotator')
cy.get('[data-cy="user-options-annotator"]').trigger('mouseout')
})
+ cy.get('[data-cy="user-options-svg"]').trigger('mouseenter').then(() => {
+ cy.get('[data-cy="uo-tooltip"]').should('be.visible').and('contain', 'svg')
+ cy.get('[data-cy="user-options-svg"]').trigger('mouseout')
+ })
})
})
})
\ No newline at end of file
diff --git a/src/atoms/UserOptions.vue b/src/atoms/UserOptions.vue
index 02db22e6..14b3f84d 100644
--- a/src/atoms/UserOptions.vue
+++ b/src/atoms/UserOptions.vue
@@ -366,7 +366,7 @@ const isInfo = ref({
-
+
{{ titles.tooltip }}
@@ -379,7 +379,7 @@ const isInfo = ref({
-
+
{{ titles.pdf }}
@@ -391,7 +391,7 @@ const isInfo = ref({
-
+
{{ titles.csv }}
@@ -404,7 +404,7 @@ const isInfo = ref({
-
+
{{ titles.img }}
@@ -413,8 +413,10 @@ const isInfo = ref({
-
-
+
+
+
+
{{ titles.svg }}
@@ -427,7 +429,7 @@ const isInfo = ref({
-
+
{{ titles.table }}
@@ -439,7 +441,7 @@ const isInfo = ref({
-
+
{{ titles.labels }}
@@ -451,20 +453,20 @@ const isInfo = ref({
-
+
{{ titles.sort }}
-
+
-
+
{{ titles.stack }}
@@ -477,7 +479,7 @@ const isInfo = ref({
-
+
{{ titles.fullscreen }}
@@ -490,7 +492,7 @@ const isInfo = ref({
-
+
{{ titles.animation }}
@@ -503,7 +505,7 @@ const isInfo = ref({
-
+
{{ titles.annotator }}
diff --git a/src/components/vue-data-ui.vue b/src/components/vue-data-ui.vue
index e8401737..4d478cb6 100644
--- a/src/components/vue-data-ui.vue
+++ b/src/components/vue-data-ui.vue
@@ -49,8 +49,8 @@ const components = {
VueUiThermometer: defineAsyncComponent(() => import('./vue-ui-thermometer.vue')),
VueUiTiremarks: defineAsyncComponent(() => import('./vue-ui-tiremarks.vue')),
VueUiTreemap: defineAsyncComponent(() => import('./vue-ui-treemap.vue')),
- VueUiVerticalBar: defineAsyncComponent(() => import('./vue-ui-vertical-bar.vue')), // delete in v4
- VueUiHorizontalBar: defineAsyncComponent(() => import('./vue-ui-vertical-bar.vue')), // v3 renaming
+ VueUiVerticalBar: defineAsyncComponent(() => import('./vue-ui-horizontal-bar.vue')), // legacy support
+ VueUiHorizontalBar: defineAsyncComponent(() => import('./vue-ui-horizontal-bar.vue')), // v3 renaming
VueUiWaffle: defineAsyncComponent(() => import('./vue-ui-waffle.vue')),
VueUiWheel: defineAsyncComponent(() => import('./vue-ui-wheel.vue')),
VueUiXy: defineAsyncComponent(() => import('./vue-ui-xy.vue')),
@@ -69,6 +69,7 @@ const components = {
VueUiCarouselTable: defineAsyncComponent(() => import('./vue-ui-carousel-table.vue')),
VueUiGizmo: defineAsyncComponent(() => import('./vue-ui-gizmo.vue')),
VueUiStackbar: defineAsyncComponent(() => import('./vue-ui-stackbar.vue')),
+ VueUiStackline: defineAsyncComponent(() => import('./vue-ui-stackline.vue')),
VueUiBullet: defineAsyncComponent(() => import('./vue-ui-bullet.vue')),
VueUiFunnel: defineAsyncComponent(() => import('./vue-ui-funnel.vue')),
VueUiHistoryPlot: defineAsyncComponent(() => import('./vue-ui-history-plot.vue')),
@@ -135,6 +136,7 @@ const componentProps = {
VueUiCarouselTable: ['config', 'dataset'],
VueUiGizmo: ['config', 'dataset'],
VueUiStackbar: ['config', 'dataset'],
+ VueUiStackline: ['config', 'dataset'],
VueUiBullet: ['config', 'dataset'],
VueUiFunnel: ['config', 'dataset'],
VueUiHistoryPlot: ['config', 'dataset'],
@@ -171,7 +173,9 @@ const emit = defineEmits([
'selectGroup',
'selectRibbon',
'toggleTable',
- 'resetZoom'
+ 'resetZoom',
+ 'showSeries',
+ 'hideSeries',
]);
const isError = computed(() => !components[props.component]);
@@ -217,6 +221,8 @@ const selectGroup = ref(() => null);
const selectRibbon = ref(() => null);
const autoSize = ref(() => null);
const resetZoom = ref(() => null);
+const showSeries = ref(() => null);
+const hideSeries = ref(() => null);
onMounted(() => {
if (isError.value) {
@@ -316,6 +322,12 @@ watch(currentComponentRef, async (newRef) => {
if (newRef.resetZoom) {
resetZoom.value = newRef.resetZoom;
}
+ if (newRef.showSeries) {
+ showSeries.value = newRef.showSeries;
+ }
+ if (newRef.hideSeries) {
+ hideSeries.value = newRef.hideSeries;
+ }
}
})
@@ -352,6 +364,8 @@ const getEventHandlers = () => {
'autoSize',
'toggleTable',
'resetZoom',
+ 'showSeries',
+ 'hideSeries'
];
const handlers = {};
eventNames.forEach(event => {
@@ -428,7 +442,9 @@ defineExpose({
selectNode,
selectGroup,
selectRibbon,
- resetZoom
+ resetZoom,
+ showSeries,
+ hideSeries
});
const notSupported = computed(() => {
diff --git a/src/components/vue-ui-3d-bar.vue b/src/components/vue-ui-3d-bar.vue
index 1fe638ec..2973b1f5 100644
--- a/src/components/vue-ui-3d-bar.vue
+++ b/src/components/vue-ui-3d-bar.vue
@@ -39,11 +39,12 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_3d_bar.json";
import BaseScanner from "../atoms/BaseScanner.vue";
const BaseIcon = defineAsyncComponent(() => import('../atoms/BaseIcon.vue'));
@@ -55,6 +56,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_3d_bar: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -161,17 +163,29 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_3d_bar[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
+ }
}
watch(() => props.config, (_newCfg) => {
@@ -791,7 +805,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -856,6 +889,9 @@ defineExpose({
+
+
+
@@ -1067,7 +1103,7 @@ defineExpose({
style="overflow: visible; position: relative"
v-if="!loading"
>
-
+
{{ applyDataLabel(
FINAL_CONFIG.style.chart.dataLabel.formatter,
bar.value,
@@ -1119,6 +1155,7 @@ defineExpose({
:y="calcMarkerOffsetY(arc, 12, 12)"
:fill="FINAL_CONFIG.style.chart.legend.color"
:font-size="FINAL_CONFIG.style.chart.legend.fontSize / 1.5"
+ :font-weight="FINAL_CONFIG.style.chart.legend.bold ? 'bold' : 'normal'"
>
{{ applyDataLabel(
FINAL_CONFIG.style.chart.dataLabel.formatter,
@@ -1138,6 +1175,7 @@ defineExpose({
:y="calcMarkerOffsetY(arc, 12, 12) + FINAL_CONFIG.style.chart.legend.fontSize / 1.5"
:fill="FINAL_CONFIG.style.chart.legend.color"
:font-size="FINAL_CONFIG.style.chart.legend.fontSize / 1.5"
+ :font-weight="FINAL_CONFIG.style.chart.legend.bold ? 'bold' : 'normal'"
>
{{ arc.name }}
@@ -1231,7 +1269,7 @@ defineExpose({
style="overflow: visible; position: relative"
v-if="!loading"
>
-
+
{{ applyDataLabel(
FINAL_CONFIG.style.chart.dataLabel.formatter,
bar.value,
@@ -1283,6 +1321,7 @@ defineExpose({
:y="calcMarkerOffsetY(arc, 12, 12)"
:fill="FINAL_CONFIG.style.chart.legend.color"
:font-size="FINAL_CONFIG.style.chart.legend.fontSize / 1.5"
+ :font-weight="FINAL_CONFIG.style.chart.legend.bold ? 'bold' : 'normal'"
>
{{ applyDataLabel(
FINAL_CONFIG.style.chart.dataLabel.formatter,
@@ -1302,6 +1341,7 @@ defineExpose({
:y="calcMarkerOffsetY(arc, 12, 12) + FINAL_CONFIG.style.chart.legend.fontSize / 1.5"
:fill="FINAL_CONFIG.style.chart.legend.color"
:font-size="FINAL_CONFIG.style.chart.legend.fontSize / 1.5"
+ :font-weight="FINAL_CONFIG.style.chart.legend.bold ? 'bold' : 'normal'"
>
{{ arc.name }}
diff --git a/src/components/vue-ui-age-pyramid.vue b/src/components/vue-ui-age-pyramid.vue
index 16466dcb..51f9c60e 100644
--- a/src/components/vue-ui-age-pyramid.vue
+++ b/src/components/vue-ui-age-pyramid.vue
@@ -34,12 +34,13 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
import { useResponsive } from "../useResponsive";
import { useNestedProp } from "../useNestedProp";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import { useTimeLabelCollision } from "../useTimeLabelCollider";
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_age_pyramid.json";
import BaseScanner from "../atoms/BaseScanner.vue";
const Tooltip = defineAsyncComponent(() => import('../atoms/Tooltip.vue'));
@@ -52,6 +53,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_age_pyramid: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -148,16 +150,26 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_age_pyramid[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return finalConfig;
}
watch(() => props.config, (_newCfg) => {
@@ -716,7 +728,26 @@ defineExpose({
:color="FINAL_CONFIG.style.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-bullet.vue b/src/components/vue-ui-bullet.vue
index a31880fe..f2985933 100644
--- a/src/components/vue-ui-bullet.vue
+++ b/src/components/vue-ui-bullet.vue
@@ -1,31 +1,48 @@
- setUserOptionsVisibility(true)" @mouseleave="() => setUserOptionsVisibility(false)">
-
+
setUserOptionsVisibility(true)"
+ @mouseleave="() => setUserOptionsVisibility(false)"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
@@ -696,6 +791,9 @@ defineExpose({
+
+
+
@@ -707,129 +805,172 @@ defineExpose({
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- {{ circle.name }}
-
-
-
-
- {{ getCircleLabel(circle) }}
-
+ }"
+ />
-
-
-
-
-
-
-
-
-
-
-
- {{ zoom.name }}
-
-
-
-
- {{ getZoomLabel() }}
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {{ circle.name }}
+
+
+
+
+ {{ getCircleLabel(circle) }}
+
+
+
+
+
+
+
@@ -839,6 +980,35 @@ defineExpose({
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
diff --git a/src/components/vue-ui-dashboard.vue b/src/components/vue-ui-dashboard.vue
index 7d057489..d2fa6381 100644
--- a/src/components/vue-ui-dashboard.vue
+++ b/src/components/vue-ui-dashboard.vue
@@ -54,8 +54,8 @@ const builtInComponents = {
VueUiTimer : defineAsyncComponent(() => import("../components/vue-ui-timer.vue")),
VueUiTiremarks : defineAsyncComponent(() => import("../components/vue-ui-tiremarks.vue")),
VueUiTreemap : defineAsyncComponent(() => import("../components/vue-ui-treemap.vue")),
- VueUiVerticalBar : defineAsyncComponent(() => import("../components/vue-ui-vertical-bar.vue")),
- VueUiHorizontalBar : defineAsyncComponent(() => import("../components/vue-ui-vertical-bar.vue")),
+ VueUiVerticalBar : defineAsyncComponent(() => import("../components/vue-ui-horizontal-bar.vue")),
+ VueUiHorizontalBar : defineAsyncComponent(() => import("../components/vue-ui-horizontal-bar.vue")),
VueUiWaffle : defineAsyncComponent(() => import("../components/vue-ui-waffle.vue")),
VueUiWheel : defineAsyncComponent(() => import("../components/vue-ui-wheel.vue")),
VueUiWordCloud : defineAsyncComponent(() => import("../components/vue-ui-word-cloud.vue")),
@@ -64,6 +64,7 @@ const builtInComponents = {
VueUiCarouselTable : defineAsyncComponent(() => import('../components/vue-ui-carousel-table.vue')),
VueUiGizmo : defineAsyncComponent(() => import('../components/vue-ui-gizmo.vue')),
VueUiStackbar : defineAsyncComponent(() => import('../components/vue-ui-stackbar.vue')),
+ VueUiStackline : defineAsyncComponent(() => import('../components/vue-ui-stackline.vue')),
VueUiBullet : defineAsyncComponent(() => import('../components/vue-ui-bullet.vue')),
VueUiFunnel : defineAsyncComponent(() => import('../components/vue-ui-funnel.vue')),
VueUiHistoryPlot : defineAsyncComponent(() => import('../components/vue-ui-history-plot.vue')),
@@ -519,7 +520,26 @@ defineExpose({
:style="{
zIndex: resolvedItems.length + 1
}"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-import { ref, computed, nextTick, onMounted, watch, defineAsyncComponent, watchEffect, onBeforeUnmount, toRefs, shallowRef } from "vue";
+import {
+ computed,
+ defineAsyncComponent,
+ nextTick,
+ onBeforeUnmount,
+ onMounted,
+ ref,
+ shallowRef,
+ toRefs,
+ watch,
+ watchEffect,
+} from "vue";
import {
applyDataLabel,
calcMarkerOffsetX,
@@ -37,12 +48,13 @@ import { useSvgExport } from "../useSvgExport.js";
import { useTimeLabels } from "../useTimeLabels";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive.js";
+import { useThemeCheck } from "../useThemeCheck.js";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import { useTimeLabelCollision } from '../useTimeLabelCollider.js';
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_donut_evolution.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import Slicer from "../atoms/Slicer.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -57,6 +69,7 @@ const VueUiDonut = defineAsyncComponent(() => import('./vue-ui-donut.vue'));
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_donut_evolution: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -340,14 +353,27 @@ function prepareConfig() {
let finalConfig = {};
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig: themes.vue_ui_donut_evolution[mergedConfig.theme] || props.config,
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
+ });
+
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ }),
+ customPalette: mergedConfig.customPalette ? mergedConfig.customPalette : themePalettes[theme] || palette
+ }
}
+
} else {
finalConfig = mergedConfig;
}
@@ -766,17 +792,50 @@ const legendConfig = computed(() => {
function segregate(id) {
if(segregated.value.includes(id)) {
segregated.value = segregated.value.filter(s => s !== id);
- emit('selectLegend', null)
+ emit('selectLegend', mutableDataset.value)
}else {
if(segregated.value.length === convertedDataset.value.length - 1) return;
segregated.value.push(id);
- emit('selectLegend', convertedDataset.value.find(d => d.uid === id));
+ emit('selectLegend', mutableDataset.value);
}
if(fixedDatapoint.value) {
fixDatapoint(drawableDataset.value.find((_, i) => i === fixedDatapointIndex.value))
}
}
+function validSeriesToToggle(name) {
+ if (!convertedDataset.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiDonutEvolution - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = convertedDataset.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiDonutEvolution - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.uid)) {
+ segregate(dp.uid);
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.uid)) {
+ segregate(dp.uid);
+ }
+}
+
const table = computed(() => {
const head = [''].concat(convertedDataset.value.filter(ds => !segregated.value.includes(ds.uid)).map(ds => {
return {
@@ -1001,6 +1060,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleAnnotator,
toggleFullscreen
@@ -1017,7 +1078,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-donut.vue b/src/components/vue-ui-donut.vue
index b333fcd9..70d106e9 100644
--- a/src/components/vue-ui-donut.vue
+++ b/src/components/vue-ui-donut.vue
@@ -48,12 +48,13 @@ import { useLoading } from "../useLoading";
import { useSvgExport } from "../useSvgExport";
import { useResponsive } from "../useResponsive";
import { useNestedProp } from "../useNestedProp";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
import Shape from "../atoms/Shape.vue";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_donut.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -67,6 +68,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_donut: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const slots = useSlots();
const props = defineProps({
@@ -305,8 +307,6 @@ function prepareChart() {
}
const uid = ref(createUid());
-
-const details = ref(null);
const isTooltip = ref(false);
const tooltipContent = ref("");
const selectedSerie = ref(null);
@@ -319,17 +319,28 @@ function prepareConfig() {
});
let finalConfig = {}
-
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig: themes.vue_ui_donut[mergedConfig.theme] || props.config,
+
+ const theme = mergedConfig.theme;
+ if (!theme) {
+ finalConfig = mergedConfig;
+ } else {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
+ });
+
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ }),
+ customPalette: mergedConfig.customPalette.length ? mergedConfig.customPalette : themePalettes[theme] || palette
+ }
}
- } else {
- finalConfig = mergedConfig;
}
// ------------------------------ OVERRIDES -----------------------------------
@@ -719,6 +730,39 @@ function segregate(index) {
})));
}
+function validSeriesToToggle(name) {
+ if (!immutableSet.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiDonut - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = immutableSet.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiDonut - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.seriesIndex)) {
+ segregate(dp.seriesIndex);
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.seriesIndex)) {
+ segregate(dp.seriesIndex);
+ }
+}
+
const _total = computed(() => FINAL_DATASET.value.reduce((sum, ds) => sum + ds.values.reduce((a, b) => a + b, 0), 0));
@@ -1231,6 +1275,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleLabels,
toggleTooltip,
@@ -1249,7 +1295,28 @@ defineExpose({
+ @close="toggleAnnotator"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-dumbbell.vue b/src/components/vue-ui-dumbbell.vue
index 02a56e55..510062dd 100644
--- a/src/components/vue-ui-dumbbell.vue
+++ b/src/components/vue-ui-dumbbell.vue
@@ -35,12 +35,13 @@ import { useLoading } from "../useLoading";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import { useTimeLabelCollision } from "../useTimeLabelCollider";
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_dumbbell.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -53,6 +54,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_dumbbell: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -169,16 +171,26 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_dumbbell[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return finalConfig;
}
watch(() => props.config, (_newCfg) => {
@@ -934,7 +946,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-flow.vue b/src/components/vue-ui-flow.vue
index d31284cd..66b3975f 100644
--- a/src/components/vue-ui-flow.vue
+++ b/src/components/vue-ui-flow.vue
@@ -34,9 +34,10 @@ import { useLoading } from "../useLoading";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_flow.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
import img from "../img";
@@ -52,6 +53,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_flow: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -82,6 +84,7 @@ const observedEl = ref(null);
const readyTeleport = ref(false);
const tableUnit = ref(null);
const userOptionsRef = ref(null);
+const tooltip = ref(null);
const isDataset = computed(() => {
return !!props.dataset && props.dataset.length;
@@ -207,14 +210,26 @@ function prepareConfig() {
let final = mergedConfig;
- if (mergedConfig.theme) {
- final = {
- ...useNestedProp({
- userConfig: themes.vue_ui_flow[mergedConfig.theme] || props.config,
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ final = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig,
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette,
- };
+ });
+
+ final = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused,
+ }),
+ customPalette: mergedConfig.customPalette.length ? mergedConfig.customPalette : themePalettes[theme] || palette,
+ };
+ }
} else {
final = mergedConfig;
}
@@ -430,22 +445,23 @@ function computeSankeyCoordinates(ds) {
let yCursor = Math.max(0, (innerH - used) / 2);
names.forEach((name, i) => {
- const h = heights[i];
- const x = p.left + levelIndex * colSpacing;
- const y = yCursor;
-
- nodeCoordinates[name] = {
- x,
- y,
- absoluteY: y,
- height: h,
- i,
- color: nodes[name].color,
- value: nodes[name].value,
- };
+ const h = heights[i];
+ const x = p.left + levelIndex * colSpacing;
+ const y = yCursor;
+
+ nodeCoordinates[name] = {
+ x,
+ y,
+ absoluteY: y,
+ height: h,
+ i,
+ color: nodes[name].color,
+ value: nodes[name].value,
+ id: createUid()
+ };
- yCursor += h;
- if (i < n - 1) yCursor += gapPx;
+ yCursor += h;
+ if (i < n - 1) yCursor += gapPx;
});
});
@@ -581,11 +597,14 @@ const selectedNodes = ref(null);
const selectedSource = ref(null);
const dataTooltipSlot = ref(null);
const useCustomFormat = ref(false);
+const selectedNodeId = ref(null);
+
function selectNode(node, index) {
segregated.value = [];
selectedNodes.value = findConnectedNodes(node.name);
selectedSource.value = node.name;
+ selectedNodeId.value = node.id;
const nodeName = node.name;
const dataset = sanitizedDataset.value;
@@ -712,6 +731,7 @@ function selectNode(node, index) {
}
function unselectNode(index) {
+ selectedNodeId.value = null;
const datapoint = dataTooltipSlot.value;
if (FINAL_CONFIG.value.events.datapointLeave) {
FINAL_CONFIG.value.events.datapointLeave({ datapoint, seriesIndex: index });
@@ -1006,6 +1026,17 @@ async function generateSvg({ isCb }) {
}
}
+async function focusNode(node, i) {
+ selectNode(node, i);
+ if (mutableConfig.value.showTooltip) {
+ await nextTick();
+ if (flowChart.value && tooltip.value) {
+ const { left, top } = flowChart.value.getBoundingClientRect();
+ tooltip.value.placeTooltip({x: (left ?? 0) + 12, y: (top ?? 0) + 12 });
+ }
+ }
+}
+
defineExpose({
getData,
getImage,
@@ -1029,7 +1060,27 @@ defineExpose({
@mouseleave="() => setUserOptionsVisibility(false)">
+ :active="isAnnotator" @close="toggleAnnotator"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1106,6 +1157,9 @@ defineExpose({
+
+
+
@@ -1150,9 +1204,17 @@ defineExpose({
-
+ `"
+ />
@@ -1256,6 +1342,7 @@ defineExpose({
import('../atoms/BaseIcon.vue'));
const Skeleton = defineAsyncComponent(() => import('./vue-ui-skeleton.vue'));
@@ -46,6 +47,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_funnel: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -178,16 +180,26 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_funnel[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return finalConfig;
}
const FINAL_CONFIG = computed({
@@ -551,7 +563,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-galaxy.vue b/src/components/vue-ui-galaxy.vue
index 3f3ef4c7..0a8ea3bf 100644
--- a/src/components/vue-ui-galaxy.vue
+++ b/src/components/vue-ui-galaxy.vue
@@ -32,16 +32,17 @@ import { throttle } from "../canvas-lib";
import { useConfig } from "../useConfig";
import { useLoading } from "../useLoading";
import { usePrinter } from "../usePrinter";
+import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_galaxy.json";
import BaseScanner from "../atoms/BaseScanner.vue";
import Title from "../atoms/Title.vue";
import Legend from "../atoms/Legend.vue";
-import { useSvgExport } from "../useSvgExport";
const Tooltip = defineAsyncComponent(() => import('../atoms/Tooltip.vue'));
const BaseIcon = defineAsyncComponent(() => import('../atoms/BaseIcon.vue'));
@@ -53,6 +54,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_galaxy: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -195,17 +197,29 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_galaxy[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
+ }
}
watch(() => props.config, (_newCfg) => {
@@ -275,6 +289,39 @@ function segregate(datapoint) {
}));
}
+function validSeriesToToggle(name) {
+ if (!immutableSet.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiGalaxy - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = immutableSet.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiGalaxy - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.id)) {
+ segregate({ id : dp.id });
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.id)) {
+ segregate({ id: dp.id });
+ }
+}
+
const immutableSet = computed(() => {
return FINAL_DATASET.value
.map((serie, i) => {
@@ -687,6 +734,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleTooltip,
toggleAnnotator,
@@ -704,7 +753,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-gauge.vue b/src/components/vue-ui-gauge.vue
index 71d9a33f..5a271413 100644
--- a/src/components/vue-ui-gauge.vue
+++ b/src/components/vue-ui-gauge.vue
@@ -39,11 +39,12 @@ import { useConfig } from "../useConfig";
import { useSvgExport } from "../useSvgExport.js";
import { useResponsive } from "../useResponsive";
import { useNestedProp } from "../useNestedProp";
+import { useThemeCheck } from "../useThemeCheck.js";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility.js";
import { useAutoSizeLabelsInsideViewbox } from "../useAutoSizeLabelsInsideViewbox.js";
import img from "../img.js";
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_gauge.json";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -51,7 +52,8 @@ const PenAndPaper = defineAsyncComponent(() => import('../atoms/PenAndPaper.vue'
const UserOptions = defineAsyncComponent(() => import('../atoms/UserOptions.vue'));
const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersion.vue'));
-const { vue_ui_gauge: DEFAULT_CONFIG } = useConfig()
+const { vue_ui_gauge: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -155,17 +157,29 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_gauge[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
+ }
}
const { isPrinting, isImaging, generatePdf, generateImage } = usePrinter({
@@ -668,7 +682,27 @@ defineExpose({
:svgRef="svgRef"
:backgroundColor="FINAL_CONFIG.style.chart.backgroundColor"
:color="FINAL_CONFIG.style.chart.color"
- :active="isAnnotator" @close="toggleAnnotator" />
+ :active="isAnnotator" @close="toggleAnnotator"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -732,6 +766,9 @@ defineExpose({
+
+
+
diff --git a/src/components/vue-ui-heatmap.vue b/src/components/vue-ui-heatmap.vue
index 907ff559..44787a35 100644
--- a/src/components/vue-ui-heatmap.vue
+++ b/src/components/vue-ui-heatmap.vue
@@ -38,6 +38,7 @@ import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
import { useTimeLabels } from "../useTimeLabels";
+import { useThemeCheck } from "../useThemeCheck";
import { useTableResponsive } from "../useTableResponsive";
import { useUserOptionState } from "../useUserOptionState";
import { useTimeLabelCollision } from "../useTimeLabelCollider";
@@ -45,7 +46,7 @@ import { useChartAccessibility } from "../useChartAccessibility";
import { useResizeObserverEffect } from '../useResizeObserverEffect';
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_heatmap.json";
import vFitText from "../directives/vFitText";
import Accordion from "./vue-ui-accordion.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -57,7 +58,8 @@ const UserOptions = defineAsyncComponent(() => import('../atoms/UserOptions.vue'
const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersion.vue'));
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
-const { vue_ui_heatmap: DEFAULT_CONFIG } = useConfig()
+const { vue_ui_heatmap: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -189,12 +191,24 @@ function prepareConfig() {
let finalConfig = {};
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig: themes.vue_ui_heatmap[mergedConfig.theme] || props.config,
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig
- }),
+ });
+
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ }),
+ }
}
} else {
finalConfig = mergedConfig;
@@ -845,7 +859,26 @@ defineExpose({
:color="FINAL_CONFIG.style.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-history-plot.vue b/src/components/vue-ui-history-plot.vue
index d0df4a9f..a8a711c7 100644
--- a/src/components/vue-ui-history-plot.vue
+++ b/src/components/vue-ui-history-plot.vue
@@ -42,12 +42,13 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import { useTimeLabelCollision } from "../useTimeLabelCollider";
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_history_plot.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -61,6 +62,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_history_plot: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -263,13 +265,26 @@ function prepareConfig() {
defaultConfig: DEFAULT_CONFIG
});
let finalConfig = {};
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig: themes.vue_ui_history_plot[mergedConfig.theme] || props.config,
+
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
+ });
+
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ }),
+ customPalette: mergedConfig.customPalette.length ? mergedConfig.customPalette : themePalettes[theme] || palette
+ }
}
} else {
finalConfig = mergedConfig;
@@ -623,6 +638,39 @@ function segregate(index) {
}
}
+function validSeriesToToggle(name) {
+ if (!formattedDataset.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiHistoryPlot - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = formattedDataset.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiHistoryPlot - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.seriesIndex)) {
+ segregate(dp.seriesIndex);
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.seriesIndex)) {
+ segregate(dp.seriesIndex);
+ }
+}
+
const legendSet = computed(() => {
return formattedDataset.value.map(ds => {
return {
@@ -983,6 +1031,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleTooltip,
toggleAnnotator,
@@ -1010,7 +1060,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-vertical-bar.cy.js b/src/components/vue-ui-horizontal-bar.cy.js
similarity index 88%
rename from src/components/vue-ui-vertical-bar.cy.js
rename to src/components/vue-ui-horizontal-bar.cy.js
index cf6b233c..6d292a7b 100644
--- a/src/components/vue-ui-vertical-bar.cy.js
+++ b/src/components/vue-ui-horizontal-bar.cy.js
@@ -1,12 +1,12 @@
-import VueUiVerticalBar from './vue-ui-vertical-bar.vue';
+import VueUiHorizontalBar from './vue-ui-horizontal-bar.vue';
import { components } from '../../cypress/fixtures/vdui-components';
import { testCommonFeatures } from '../../cypress/fixtures';
-const { config, dataset } = components.find(c => c.name === 'VueUiVerticalBar');
+const { config, dataset } = components.find(c => c.name === 'VueUiHorizontalBar');
-describe('
', () => {
+describe('
', () => {
it('renders', () => {
- cy.mount(VueUiVerticalBar, {
+ cy.mount(VueUiHorizontalBar, {
props: {
dataset,
config
@@ -35,7 +35,7 @@ describe('
', () => {
});
it('emits', () => {
- cy.mount(VueUiVerticalBar, {
+ cy.mount(VueUiHorizontalBar, {
props: {
dataset,
config
diff --git a/src/components/vue-ui-horizontal-bar.vue b/src/components/vue-ui-horizontal-bar.vue
new file mode 100644
index 00000000..64e83861
--- /dev/null
+++ b/src/components/vue-ui-horizontal-bar.vue
@@ -0,0 +1,2072 @@
+
+
+
+ setUserOptionsVisibility(true)" @mouseleave="() => setUserOptionsVisibility(false)">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
segregate(legend.id)">
+
+
+
+
+
+
+ {{ legend.name }}:
+ {{
+ applyDataLabel(
+ FINAL_CONFIG.style.chart.layout.bars.dataLabels.value.formatter,
+ legend.value,
+ dataLabel({
+ p: FINAL_CONFIG.style.chart.legend.prefix,
+ v: legend.value,
+ s: FINAL_CONFIG.style.chart.legend.suffix,
+ r: FINAL_CONFIG.style.chart.legend.roundingValue,
+ }),
+ { datapoint: legend, seriesIndex: index }
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ getParentName(serie, i) }}
+
+
+
+ {{ getParentDataLabel(serie, i) }}
+
+
+
+
+
+
+
+
+ {{ serie.name }}
+
+
+
+
+
+
+
+
+ {{ serie.name }}
+
+
+
+
+
+
+
+
+ {{ makeDataLabel(serie.value, serie, i, serie.sign) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
segregate(legend.id)">
+
+
+
+
+
+
+ {{ legend.name }}:
+ {{
+ applyDataLabel(
+ FINAL_CONFIG.style.chart.layout.bars.dataLabels.value.formatter,
+ legend.value,
+ dataLabel({
+ p: FINAL_CONFIG.style.chart.legend.prefix,
+ v: legend.value,
+ s: FINAL_CONFIG.style.chart.legend.suffix,
+ r: FINAL_CONFIG.style.chart.legend.roundingValue,
+ }),
+ { datapoint: legend, seriesIndex: index }
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tableComponent.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ FINAL_CONFIG.style.chart.title.text
+ }}
+ {{
+ FINAL_CONFIG.style.chart.title.subtitle.text
+ }}
+
+
+
+
+
+ {{ th }}
+
+
+
+
+
+
+
+ ∑ {{ FINAL_CONFIG.table.td.prefix
+ }}{{
+ isNaN(total)
+ ? ""
+ : total.toFixed(FINAL_CONFIG.table.td.roundingValue)
+ }}{{ FINAL_CONFIG.table.td.suffix }}
+
+
+ 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ⬤ {{
+ tr.parentName }}
+
+
+
+
+ {{ FINAL_CONFIG.table.td.prefix
+ }}{{
+ ["", NaN, undefined].includes(tr.parentValue)
+ ? ""
+ : tr.parentValue.toFixed(
+ FINAL_CONFIG.table.td.roundingValue
+ )
+ }}{{ FINAL_CONFIG.table.td.suffix }}
+
+
+
+
+ {{
+ ["", NaN, undefined].includes(tr.percentageToTotal)
+ ? ""
+ : `${(tr.percentageToTotal * 100).toFixed(
+ FINAL_CONFIG.table.td.roundingPercentage
+ )}%`
+ }}
+
+
+
+
+ {{ tr.childName }}
+
+
+
+
+ {{ FINAL_CONFIG.table.td.prefix
+ }}{{
+ ["", NaN, undefined].includes(tr.childValue)
+ ? ""
+ : tr.childValue.toFixed(
+ FINAL_CONFIG.table.td.roundingValue
+ )
+ }}{{ FINAL_CONFIG.table.td.suffix }}
+
+
+
+
+ {{
+ ["", NaN, undefined].includes(
+ tr.childPercentageToParent
+ )
+ ? ""
+ : `${(tr.childPercentageToParent * 100).toFixed(
+ FINAL_CONFIG.table.td.roundingPercentage
+ )}%`
+ }}
+
+
+
+
+ {{
+ ["", NaN, undefined].includes(
+ tr.childPercentageToTotal
+ )
+ ? ""
+ : `${(tr.childPercentageToTotal * 100).toFixed(
+ FINAL_CONFIG.table.td.roundingPercentage
+ )}%`
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-molecule.vue b/src/components/vue-ui-molecule.vue
index 22d51554..5fbd6b1f 100644
--- a/src/components/vue-ui-molecule.vue
+++ b/src/components/vue-ui-molecule.vue
@@ -30,11 +30,12 @@ import { useConfig } from "../useConfig";
import { useLoading } from "../useLoading";
import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
+import { useThemeCheck } from "../useThemeCheck";
import { useNestedProp } from "../useNestedProp";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_molecule.json";
import usePanZoom from "../usePanZoom";
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -52,6 +53,7 @@ const RecursiveCircles = defineAsyncComponent(() => import('../atoms/RecursiveCi
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_molecule: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -169,17 +171,29 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_molecule[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
+ }
}
watch(() => props.config, (_newCfg) => {
@@ -688,7 +702,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-mood-radar.vue b/src/components/vue-ui-mood-radar.vue
index ba2c8554..469f4753 100644
--- a/src/components/vue-ui-mood-radar.vue
+++ b/src/components/vue-ui-mood-radar.vue
@@ -30,11 +30,12 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_mood_radar.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -47,6 +48,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_mood_radar: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -197,16 +199,26 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_mood_radar[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return finalConfig;
}
watch(() => props.config, (_newCfg) => {
@@ -606,7 +618,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-nested-donuts.vue b/src/components/vue-ui-nested-donuts.vue
index cc5a04bc..1440c3b8 100644
--- a/src/components/vue-ui-nested-donuts.vue
+++ b/src/components/vue-ui-nested-donuts.vue
@@ -43,11 +43,12 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_nested_donuts.json";
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -61,6 +62,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_nested_donuts: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -187,15 +189,25 @@ function prepareConfig() {
let finalConfig = {};
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig:
- themes.vue_ui_nested_donuts[mergedConfig.theme] || props.config,
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig,
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette,
- };
+ });
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused,
+ }),
+ customPalette: mergedConfig.customPalette.length ? mergedConfig.customPalette : themePalettes[theme] || palette,
+ };
+ }
} else {
finalConfig = mergedConfig;
}
@@ -746,6 +758,58 @@ function segregateDonut(item) {
}
}
+function validSeriesToToggle(name) {
+ if (!immutableDataset.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiNestedDonuts - There are no series to show.');
+ }
+ return null;
+ }
+
+ const dp = immutableDataset.value.flatMap(d => d.series).filter((el) => el.name === name)
+
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiNestedDonuts - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+
+ if (Array.isArray(dp)) {
+ dp.forEach(el => {
+ if (segregated.value.includes(el.id)) {
+ segregateDonut({ id : el.id });
+ }
+ })
+ } else {
+ if (segregated.value.includes(dp.id)) {
+ segregateDonut({ id: dp.id });
+ }
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (Array.isArray(dp)) {
+ dp.forEach(el => {
+ if (!segregated.value.includes(el.id)) {
+ segregateDonut({ id: el.id });
+ }
+ })
+ } else {
+ if (!segregated.value.includes(dp.id)) {
+ segregateDonut({ id: dp.id });
+ }
+ }
+}
+
const donutThickness = computed(() => {
return (
(donutSize.value / immutableDataset.value.length) *
@@ -1347,6 +1411,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleLabels,
toggleTooltip,
@@ -1363,7 +1429,27 @@ defineExpose({
@mouseleave="() => setUserOptionsVisibility(false)">
+ :active="isAnnotator" @close="toggleAnnotator"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1443,6 +1529,9 @@ defineExpose({
+
+
+
diff --git a/src/components/vue-ui-onion.vue b/src/components/vue-ui-onion.vue
index 2a9149cc..2ee44785 100644
--- a/src/components/vue-ui-onion.vue
+++ b/src/components/vue-ui-onion.vue
@@ -34,13 +34,14 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport.js";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck.js";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility.js";
import { useAutoSizeLabelsInsideViewbox } from "../useAutoSizeLabelsInsideViewbox.js";
import img from "../img.js";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_onion.json";
import BaseScanner from "../atoms/BaseScanner.vue";
const Tooltip = defineAsyncComponent(() => import('../atoms/Tooltip.vue'));
@@ -53,6 +54,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_onion: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -140,17 +142,29 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_onion[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
+ }
}
watch(() => props.config, (_newCfg) => {
@@ -482,11 +496,45 @@ function segregate(id) {
if(segregated.value.includes(id)) {
segregated.value = segregated.value.filter(el => el !== id);
}else {
+ if (segregated.value.length === immutableDataset.value.length - 1) return;
segregated.value.push(id)
}
emit('selectLegend', mutableDataset.value)
}
+function validSeriesToToggle(name) {
+ if (!immutableDataset.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiOnion - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = immutableDataset.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiOnion - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.id)) {
+ segregate(dp.id);
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.id)) {
+ segregate(dp.id);
+ }
+}
+
function getData() {
return mutableDataset.value;
}
@@ -733,6 +781,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleTooltip,
toggleAnnotator,
@@ -756,7 +806,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-parallel-coordinate-plot.vue b/src/components/vue-ui-parallel-coordinate-plot.vue
index ffaccdd8..df80bcab 100644
--- a/src/components/vue-ui-parallel-coordinate-plot.vue
+++ b/src/components/vue-ui-parallel-coordinate-plot.vue
@@ -1,5 +1,16 @@
diff --git a/src/components/vue-ui-stackbar.vue b/src/components/vue-ui-stackbar.vue
index 7863d18d..581d7965 100755
--- a/src/components/vue-ui-stackbar.vue
+++ b/src/components/vue-ui-stackbar.vue
@@ -49,13 +49,14 @@ import { useSvgExport } from "../useSvgExport.js";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
import { useTimeLabels } from "../useTimeLabels";
+import { useThemeCheck } from "../useThemeCheck.js";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import { useTimeLabelCollision } from '../useTimeLabelCollider.js';
import img from "../img";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
import Shape from "../atoms/Shape.vue";
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_stackbar.json";
import locales from '../locales/locales.json';
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import BaseScanner from "../atoms/BaseScanner.vue";
@@ -71,6 +72,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_stackbar: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const slots = useSlots();
const props = defineProps({
@@ -176,6 +178,9 @@ const { loading, FINAL_DATASET, manualLoading } = useLoading({
dataLabels: { show: false },
},
grid: {
+ frame: {
+ stroke: '#6A6A6A'
+ },
scale: {
scaleMin: 0,
scaleMax: 40
@@ -231,13 +236,26 @@ function prepareConfig() {
defaultConfig: DEFAULT_CONFIG,
});
let finalConfig = {};
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig: themes.vue_ui_stackbar[mergedConfig.theme] || props.config,
+
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
+ });
+
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ }),
+ customPalette: mergedConfig.customPalette.length ? mergedConfig.customPalette : themePalettes[theme] || palette
+ }
}
} else {
finalConfig = mergedConfig;
@@ -498,19 +516,55 @@ const updateOffsetRight = throttle((w) => {
offsetRight.value = w + FINAL_CONFIG.value.style.chart.bars.totalValues.fontSize
}, 100);
+
+function computeRightOverhang() {
+ if (FINAL_CONFIG.value.orientation !== 'horizontal') return 0;
+
+ const group = sumRight.value;
+ if (!group) return 0;
+
+ const texts = Array.from(group.querySelectorAll('text'));
+ if (!texts.length) return 0;
+
+ let maxRight = -Infinity;
+ for (const t of texts) {
+ try {
+ const box = t.getBBox();
+ const right = box.x + box.width;
+ if (right > maxRight) maxRight = right;
+ } catch (_) {
+ //
+ }
+ }
+
+ const overhang = Math.max(0, maxRight - (drawingArea.value?.right ?? 0));
+ return overhang;
+}
+
watchEffect((onInvalidate) => {
- if (FINAL_CONFIG.value.orientation === 'vertical') return;
+ if (FINAL_CONFIG.value.orientation !== 'horizontal') return;
const el = sumRight.value;
- if (!el) return
+ if (!el) return;
- const observer = new ResizeObserver(entries => {
- updateOffsetRight(entries[0].contentRect.width)
- })
- observer.observe(el)
- onInvalidate(() => observer.disconnect())
+ const onChange = () => {
+ const overhang = computeRightOverhang();
+ updateOffsetRight(overhang);
+ };
+
+ onChange();
+ const resizeObserver = new ResizeObserver(onChange);
+ resizeObserver.observe(el);
+ const mutationObserver = new MutationObserver(onChange);
+ mutationObserver.observe(el, { childList: true, subtree: true, characterData: true });
+
+ onInvalidate(() => {
+ resizeObserver.disconnect();
+ mutationObserver.disconnect();
+ });
});
+
onBeforeUnmount(() => {
labelsXHeight.value = 0;
offsetRight.value = 0;
@@ -710,7 +764,12 @@ const datasetTotals = computed(() => {
const datasetTotalsMinimap = computed(() => {
if (!FINAL_CONFIG.value.style.chart.zoom.minimap.show) return [];
- return sumSeries(unmutableDataset.value.filter(ds => !segregated.value.includes(ds.id)))
+ return sumSeries(unmutableDataset.value.map(ds => {
+ return {
+ ...ds,
+ series: ds.series.map(d => d ?? 0)
+ }
+ }).filter(ds => !segregated.value.includes(ds.id)))
});
const allMinimaps = computed(() => {
@@ -1182,6 +1241,7 @@ function useTooltip(seriesIndex) {
}
const sum = datapoint.map(d => Math.abs(d.value)).reduce((a, b) => a + b, 0);
+ const sumLabel = datapoint.map(d => forceValidValue(d.value)).reduce((a, b) => a + b, 0);
if (isFunction(customFormat) && functionReturnsString(() => customFormat({
seriesIndex,
@@ -1198,6 +1258,8 @@ function useTooltip(seriesIndex) {
} else {
const {
showValue,
+ showTotal,
+ totalTranslation,
showPercentage,
borderColor,
roundingValue,
@@ -1210,6 +1272,25 @@ function useTooltip(seriesIndex) {
html += `${FINAL_CONFIG.value.style.chart.tooltip.useDefaultTimeFormat ? timeLabels.value[seriesIndex]?.text : preciseAllTimeLabelsTooltip.value[seriesIndex]?.text || allTimeLabels.value[seriesIndex]?.text || ''}
`;
}
+ if (showTotal) {
+ html += `
+ ${totalTranslation}:
+
+ ${applyDataLabel(
+ FINAL_CONFIG.value.style.chart.bars.dataLabels.formatter,
+ sumLabel,
+ dataLabel({
+ p: FINAL_CONFIG.value.style.chart.bars.dataLabels.prefix,
+ v: sumLabel,
+ s: FINAL_CONFIG.value.style.chart.bars.dataLabels.suffix,
+ r: roundingValue
+ }),
+ { datapoint: { name: totalTranslation, value: sumLabel } }
+ )}
+
+
`
+ }
+
const parenthesis = [
showValue && showPercentage ? '(' : '',
showValue && showPercentage ? ')' : '',
@@ -1219,12 +1300,16 @@ function useTooltip(seriesIndex) {
html += `
${slots.pattern ? ` ` : ''}
- ${ds.name}${showValue || showPercentage ? ':' : ''} ${showValue ? dataLabel({
- p: FINAL_CONFIG.value.style.chart.bars.dataLabels.prefix,
- v: ds.value,
- s: FINAL_CONFIG.value.style.chart.bars.dataLabels.suffix,
- r: roundingValue,
- }) : ''} ${parenthesis[0]}${showPercentage ? dataLabel({
+ ${ds.name}${showValue || showPercentage ? ':' : ''} ${showValue ? applyDataLabel(
+ FINAL_CONFIG.value.style.chart.bars.dataLabels.formatter,
+ ds.value,
+ dataLabel({
+ p: FINAL_CONFIG.value.style.chart.bars.dataLabels.prefix,
+ v: ds.value,
+ s: FINAL_CONFIG.value.style.chart.bars.dataLabels.suffix,
+ r: roundingValue,
+ }, { datapoint: ds })
+ ) : ''} ${parenthesis[0]}${showPercentage ? dataLabel({
v: isNaN(ds.value / sum) ? 0 : Math.abs(ds.value) / sum * 100, // Negs are absed to show relative proportion to absolute total. It's opinionated.
s: '%',
r: roundingPercentage,
@@ -1342,14 +1427,47 @@ const dataTable = computed(() => {
return { head, body: body.slice(0, slicer.value.end - slicer.value.start), config, colNames }
});
-function segregate(index, item) {
- emit('selectLegend', formattedDataset.value.find(el => el.absoluteIndex === index));
+function segregate(item) {
if (segregated.value.includes(item.id)) {
segregated.value = segregated.value.filter(el => el !== item.id);
} else {
if ( segregated.value.length === unmutableDataset.value.length - 1) return;
segregated.value.push(item.id);
}
+ emit('selectLegend', formattedDataset.value)
+}
+
+function validSeriesToToggle(name) {
+ if (!unmutableDataset.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiStackbar - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = unmutableDataset.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiStackbar - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.id)) {
+ segregate({ id : dp.id });
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.id)) {
+ segregate({ id: dp.id });
+ }
}
const legendSet = computed(() => {
@@ -1362,7 +1480,7 @@ const legendSet = computed(() => {
return {
...ds,
opacity: segregated.value.includes(ds.id) ? 0.5 : 1,
- segregate: () => segregate(ds.absoluteIndex, ds),
+ segregate: () => segregate(ds),
isSegregated: segregated.value.includes(ds.id)
}
});
@@ -1583,6 +1701,66 @@ function selectX({ seriesIndex, datapoint }) {
})
}
+function getZeroPositions() {
+ const y0 = yLabels.value?.[0]?.zero ?? drawingArea.value.bottom;
+ return { y0 };
+}
+
+function placeLabelTotalY(index) {
+ const { y0 } = getZeroPositions();
+ const cfg = FINAL_CONFIG.value.style.chart.bars.totalValues;
+ const pad = Math.max(2, (cfg.fontSize * 0.3) + cfg.offsetY);
+
+ let minY = Infinity;
+ let hasPos = false;
+
+ for (const dp of formattedDataset.value || []) {
+ const v = dp?.series?.[index] ?? 0;
+ const h = dp?.height?.[index] ?? 0;
+ const y = dp?.y?.[index];
+ if (v > 0 && h > 0 && Number.isFinite(y)) {
+ hasPos = true;
+ if (y < minY) minY = y;
+ }
+ }
+
+ const topY = hasPos && Number.isFinite(minY) ? minY : y0;
+ const rawY = topY - pad;
+
+ const clampedY = Math.min(
+ Math.max(rawY, 0),
+ drawingArea.value.bottom
+ );
+
+ return clampedY;
+}
+
+
+
+function placeLabelTotalX(index) {
+ const { x0 } = getZeroPositions();
+ const pad = Math.max(2, (FINAL_CONFIG.value.style.chart.bars.totalValues.fontSize * 0.3) + FINAL_CONFIG.value.style.chart.bars.totalValues.offsetX);
+
+ let rightMost = -Infinity;
+ let hasPos = false;
+
+ for (const dp of formattedDataset.value || []) {
+ const v = dp?.series?.[index] ?? 0;
+ const x = dp?.horizontal_x?.[index];
+ const wRaw = dp?.horizontal_width?.[index];
+ const w = Number.isFinite(wRaw) ? Math.max(0, wRaw) : 0;
+ if (!Number.isFinite(x)) continue;
+
+ if (v > 0 && w > 0) {
+ hasPos = true;
+ rightMost = Math.max(rightMost, x + w);
+ }
+ }
+
+ const baseX = hasPos && Number.isFinite(rightMost) ? rightMost : x0;
+ return baseX + pad;
+}
+
defineExpose({
getData,
getImage,
@@ -1590,6 +1768,8 @@ defineExpose({
generateCsv,
generateImage,
generateSvg,
+ hideSeries,
+ showSeries,
toggleTable,
toggleLabels,
toggleTooltip,
@@ -1615,7 +1795,27 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1691,6 +1891,9 @@ defineExpose({
+
+
+
@@ -1737,6 +1940,23 @@ defineExpose({
+
+
+
-
+
diff --git a/src/components/vue-ui-stackline.cy.js b/src/components/vue-ui-stackline.cy.js
new file mode 100644
index 00000000..3b64bd13
--- /dev/null
+++ b/src/components/vue-ui-stackline.cy.js
@@ -0,0 +1,54 @@
+import VueUiStackline from "./vue-ui-stackline.vue";
+import { components } from "../../cypress/fixtures/vdui-components";
+import { testCommonFeatures } from "../../cypress/fixtures";
+
+const { dataset, config } = components.find(c => c.name === 'VueUiStackline');
+
+describe('
', () => {
+
+ function commonTest() {
+ testCommonFeatures({
+ userOptions: true,
+ title: true,
+ subtitle: true,
+ slicer: true,
+ dataTable: true,
+ legend: true,
+ });
+
+ cy.log('axes');
+ cy.get('[data-cy="line-axis-x"]').should('exist');
+ cy.get('[data-cy="line-axis-y"]').should('exist');
+ cy.get('[data-cy="axis-label-x"]').should('exist').and('be.visible').and('contain', config.style.chart.grid.x.axisName.text)
+ cy.get('[data-cy="axis-label-y"]').should('exist').and('be.visible').and('contain', config.style.chart.grid.y.axisName.text)
+
+ cy.log('scale labels');
+ cy.get('[data-cy="scale-line-y"]').should('exist').and('have.length', 9);
+ cy.get('[data-cy="scale-label-y"]').as('yLabels').should('exist').and('be.visible').and('have.length', 9);
+ cy.get('@yLabels').first().contains(-60)
+ cy.get('@yLabels').last().contains(100)
+
+ cy.log('time labels');
+ cy.get('[data-cy="time-label"]').as('timeLabels').should('exist').and('be.visible').and('have.length', Math.max(...dataset.map(d => d.series.length)));
+ cy.get('@timeLabels').each((label, i) => {
+ cy.wrap(label).as('label');
+ cy.get('@label').contains(i);
+ });
+
+ cy.log('total labels');
+ cy.get('[data-cy="label-total"]').should('exist').and('be.visible').and('have.length', Math.max(...dataset.map(d => d.series.length)));
+
+ cy.log('datapoint labels');
+ cy.get('[data-cy="label-datapoint"]').should('exist').and('be.visible');
+ }
+
+ it('renders', () => {
+ cy.mount(VueUiStackline, {
+ props: {
+ dataset,
+ config
+ }
+ }).then(commonTest);
+ });
+
+});
\ No newline at end of file
diff --git a/src/components/vue-ui-stackline.vue b/src/components/vue-ui-stackline.vue
new file mode 100644
index 00000000..cd2a5782
--- /dev/null
+++ b/src/components/vue-ui-stackline.vue
@@ -0,0 +1,3089 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ FINAL_CONFIG.style.chart.grid.x.axisName.text }}
+
+
+
+
+ {{ FINAL_CONFIG.style.chart.grid.y.axisName.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ applyDataLabel(
+ FINAL_CONFIG.style.chart.grid.y.axisLabels.formatter,
+ yLabel.value,
+ dataLabel({
+ p: FINAL_CONFIG.style.chart.lines.dataLabels.prefix,
+ v: yLabel.value,
+ s: FINAL_CONFIG.style.chart.lines.dataLabels.suffix,
+ r: FINAL_CONFIG.style.chart.grid.y.axisLabels.rounding,
+ }),
+ { datapoint: yLabel }
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ selectTimeLabel(timeLabel, i)"
+ >
+ {{ timeLabel.text }}
+
+
+ selectTimeLabel(timeLabel, i)"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ FINAL_CONFIG.style.chart.lines.showDistributedPercentage && FINAL_CONFIG.style.chart.lines.distributed
+ ? plotDataLabelPercentage(dp.proportions[j] * 100, dp, i, dp.rel[j])
+ : plotDataLabel(dp.series[j], dp, i, dp.rel[j], dp.signedSeries[j]) }}
+
+
+
+
+
+
+
+ {{ plotDataLabel(total.value, total, i, i, total.sign) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
legend.segregate()"
+ >
+
+
+
+
+
+
+ {{ legend.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tableComponent.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ !isNaN(Number(td)) ? dataLabel({
+ p: FINAL_CONFIG.style.chart.lines.dataLabels.prefix,
+ v: td,
+ s: FINAL_CONFIG.style.chart.lines.dataLabels.suffix,
+ r: FINAL_CONFIG.table.td.roundingValue,
+ }) : td }}
+
+
+
+
+
+
+
setPrecog('end', v)"
+ @futureStart="v => setPrecog('start', v)"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/vue-ui-strip-plot.vue b/src/components/vue-ui-strip-plot.vue
index 4bde871a..8d787234 100644
--- a/src/components/vue-ui-strip-plot.vue
+++ b/src/components/vue-ui-strip-plot.vue
@@ -43,13 +43,14 @@ import { usePrinter } from "../usePrinter";
import { useSvgExport } from "../useSvgExport";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import { useTimeLabelCollision } from "../useTimeLabelCollider";
import img from "../img";
import Shape from "../atoms/Shape.vue";
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_strip_plot.json";
import BaseScanner from "../atoms/BaseScanner.vue";
const Tooltip = defineAsyncComponent(() => import('../atoms/Tooltip.vue'));
@@ -62,6 +63,7 @@ const PackageVersion = defineAsyncComponent(() => import('../atoms/PackageVersio
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_strip_plot: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
config: {
@@ -210,17 +212,29 @@ function prepareConfig() {
userConfig: props.config,
defaultConfig: DEFAULT_CONFIG
});
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_strip_plot[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
- }
- } else {
+
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
return mergedConfig;
}
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
+ }
}
watch(() => props.config, async (_newCfg) => {
@@ -857,7 +871,26 @@ defineExpose({
:color="FINAL_CONFIG.style.chart.color"
:active="isAnnotator"
@close="toggleAnnotator"
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/vue-ui-table-heatmap.vue b/src/components/vue-ui-table-heatmap.vue
index ad9621b2..a4d43fcb 100644
--- a/src/components/vue-ui-table-heatmap.vue
+++ b/src/components/vue-ui-table-heatmap.vue
@@ -1,5 +1,13 @@
- setUserOptionsVisibility(true)" @mouseleave="() => setUserOptionsVisibility(false)">
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -766,13 +856,19 @@ function useTooltip(word, index) {
-
-
+
+
+
{{ word.name }}
@@ -906,19 +998,36 @@ function useTooltip(word, index) {
\ No newline at end of file
+
+.wc-finalized text {
+ transition: fill-opacity 0.25s ease-out;
+}
+
+.vue-ui-word-cloud[data-resizing="true"] .vue-ui-word-cloud-word,
+.vue-ui-word-cloud[data-relayout="true"] .vue-ui-word-cloud-word {
+ transition: none;
+}
+
+
diff --git a/src/components/vue-ui-world.vue b/src/components/vue-ui-world.vue
index 968666a3..db30ddb9 100644
--- a/src/components/vue-ui-world.vue
+++ b/src/components/vue-ui-world.vue
@@ -800,7 +800,27 @@ defineExpose({
+ @close="toggleAnnotator"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -874,6 +894,9 @@ defineExpose({
+
+
+
diff --git a/src/components/vue-ui-xy-canvas.vue b/src/components/vue-ui-xy-canvas.vue
index 2344fdf0..1fe7fab2 100644
--- a/src/components/vue-ui-xy-canvas.vue
+++ b/src/components/vue-ui-xy-canvas.vue
@@ -51,10 +51,11 @@ import { useDateTime } from "../useDateTime";
import { useNestedProp } from "../useNestedProp";
import { useResponsive } from "../useResponsive";
import { useTimeLabels } from "../useTimeLabels";
+import { useThemeCheck } from "../useThemeCheck";
import { useUserOptionState } from "../useUserOptionState";
import { useChartAccessibility } from "../useChartAccessibility";
import img from "../img";
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_xy_canvas.json";
import locales from '../locales/locales.json';
import Legend from "../atoms/Legend.vue"; // Must be ready in responsive mode
import Title from "../atoms/Title.vue"; // Must be ready in responsive mode
@@ -70,6 +71,7 @@ const NonSvgPenAndPaper = defineAsyncComponent(() => import('../atoms/NonSvgPenA
const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDraggableDialog.vue'));
const { vue_ui_xy_canvas: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const props = defineProps({
dataset: {
@@ -219,13 +221,25 @@ function prepareConfig() {
let finalConfig = {};
- if (mergedConfig.theme) {
- finalConfig = {
- ...useNestedProp({
- userConfig: themes.vue_ui_xy_canvas[mergedConfig.theme] || props.config,
+ const theme = mergedConfig.theme;
+
+ if (theme) {
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ finalConfig = mergedConfig;
+ } else {
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || palette
+ });
+
+ finalConfig = {
+ ...useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ }),
+ customPalette: mergedConfig.customPalette.length ? mergedConfig.customPalette : themePalettes[theme] || palette
+ }
}
} else {
finalConfig = mergedConfig;
@@ -1850,6 +1864,39 @@ function segregate(index) {
debounceCanvasResize();
}
+function validSeriesToToggle(name) {
+ if (!dsCopy.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiXyCanvas - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = dsCopy.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiXyCanvas - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregated.value.includes(dp.absoluteIndex)) {
+ segregate(dp.absoluteIndex);
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregated.value.includes(dp.absoluteIndex)) {
+ segregate(dp.absoluteIndex);
+ }
+}
+
const legendSet = computed(() => {
return dsCopy.value.map((ds, i) => {
return {
@@ -2048,6 +2095,8 @@ defineExpose({
generateCsv,
generatePdf,
generateImage,
+ hideSeries,
+ showSeries,
toggleTable,
toggleLabels,
toggleStack,
diff --git a/src/components/vue-ui-xy.vue b/src/components/vue-ui-xy.vue
index c7bce320..e10ca7fd 100644
--- a/src/components/vue-ui-xy.vue
+++ b/src/components/vue-ui-xy.vue
@@ -63,11 +63,12 @@ import { useLoading } from '../useLoading.js';
import { useDateTime } from '../useDateTime.js';
import { useSvgExport } from '../useSvgExport.js';
import { useNestedProp } from '../useNestedProp';
+import { useThemeCheck } from '../useThemeCheck.js';
import { useTimeLabels } from '../useTimeLabels.js';
import { useTimeLabelCollision } from '../useTimeLabelCollider.js';
import img from '../img.js';
import Title from '../atoms/Title.vue';
-import themes from "../themes.json";
+import themes from "../themes/vue_ui_xy.json";
import Shape from '../atoms/Shape.vue';
import BaseScanner from '../atoms/BaseScanner.vue';
import SlicerPreview from '../atoms/SlicerPreview.vue'; // v3
@@ -105,7 +106,9 @@ const BaseDraggableDialog = defineAsyncComponent(() => import('../atoms/BaseDrag
const emit = defineEmits(['selectTimeLabel', 'selectX', 'selectLegend']);
const SLOTS = useSlots();
const instance = getCurrentInstance();
+
const { vue_ui_xy: DEFAULT_CONFIG } = useConfig();
+const { isThemeValid, warnInvalidTheme } = useThemeCheck();
const chart = ref(null);
const chartTitle = ref(null);
@@ -306,16 +309,27 @@ function prepareConfig() {
}
// ----------------------------------------------------------------------------
- if (mergedConfig.theme) {
- return {
- ...useNestedProp({
- userConfig: themes.vue_ui_xy[mergedConfig.theme] || props.config,
- defaultConfig: mergedConfig
- }),
- customPalette: themePalettes[mergedConfig.theme] || props.palette
- }
- } else {
- return mergedConfig
+ const theme = mergedConfig.theme;
+ if (!theme) return mergedConfig;
+
+ if (!isThemeValid.value(mergedConfig)) {
+ warnInvalidTheme(mergedConfig);
+ return mergedConfig;
+ }
+
+ const fused = useNestedProp({
+ userConfig: themes[theme] || props.config,
+ defaultConfig: mergedConfig
+ });
+
+ const finalConfig = useNestedProp({
+ userConfig: props.config,
+ defaultConfig: fused
+ });
+
+ return {
+ ...finalConfig,
+ customPalette: finalConfig.customPalette.length ? finalConfig.customPalette : themePalettes[theme] || palette
}
}
@@ -724,18 +738,18 @@ const drawingArea = computed(() => {
}
}
- const _width = width.value - _scaleLabelX - FINAL_CONFIG.value.chart.grid.labels.yAxis.crosshairSize - progressionLabelOffsetX - FINAL_CONFIG.value.chart.padding.left - FINAL_CONFIG.value.chart.padding.right;
+ const _width = width.value - _scaleLabelX - FINAL_CONFIG.value.chart.grid.labels.yAxis.crosshairSize - progressionLabelOffsetX - FINAL_CONFIG.value.chart.padding?.left - FINAL_CONFIG.value.chart.padding?.right;
const xPadding = FINAL_CONFIG.value.chart.grid.position === 'middle' ? 0 : _width / maxSeries.value / 2;
return {
- top: FINAL_CONFIG.value.chart.padding.top + topOffset,
- right: width.value - progressionLabelOffsetX - FINAL_CONFIG.value.chart.padding.right,
- bottom: height.value - timeLabelsY.value - FINAL_CONFIG.value.chart.padding.bottom - FINAL_CONFIG.value.chart.grid.labels.axis.xLabelOffsetY,
- left: _scaleLabelX + FINAL_CONFIG.value.chart.grid.labels.yAxis.crosshairSize - xPadding + FINAL_CONFIG.value.chart.padding.left,
- height: height.value - timeLabelsY.value - FINAL_CONFIG.value.chart.padding.top -FINAL_CONFIG.value.chart.padding.bottom - topOffset - FINAL_CONFIG.value.chart.grid.labels.axis.xLabelOffsetY,
+ top: FINAL_CONFIG.value.chart.padding?.top + topOffset,
+ right: width.value - progressionLabelOffsetX - FINAL_CONFIG.value.chart.padding?.right,
+ bottom: height.value - timeLabelsY.value - FINAL_CONFIG.value.chart.padding?.bottom - FINAL_CONFIG.value.chart.grid.labels.axis.xLabelOffsetY,
+ left: _scaleLabelX + FINAL_CONFIG.value.chart.grid.labels.yAxis.crosshairSize - xPadding + FINAL_CONFIG.value.chart.padding?.left,
+ height: height.value - timeLabelsY.value - FINAL_CONFIG.value.chart.padding?.top -FINAL_CONFIG.value.chart.padding?.bottom - topOffset - FINAL_CONFIG.value.chart.grid.labels.axis.xLabelOffsetY,
width: _width,
scaleLabelX: _scaleLabelX,
individualOffsetX
@@ -746,12 +760,12 @@ const gridVerticalLines = computed(() => {
const extra = FINAL_CONFIG.value.chart.grid.position === 'middle' ? 1 : 0
const count = maxSeries.value + extra
- const topY = forceValidValue(drawingArea.value.top)
- const bottomY = forceValidValue(drawingArea.value.bottom)
+ const topY = forceValidValue(drawingArea.value?.top)
+ const bottomY = forceValidValue(drawingArea.value?.bottom)
return Array.from({ length: count })
.map((_, i) => {
- const x = (drawingArea.value.width / maxSeries.value) * i + drawingArea.value.left + xPadding.value
+ const x = (drawingArea.value.width / maxSeries.value) * i + drawingArea.value?.left + xPadding.value
return `M${x},${topY} L${x},${bottomY}`
})
.join(' ')
@@ -768,13 +782,13 @@ const crosshairsX = computed(() => {
.map((label, i) => {
if (!label || !label.text) return null;
- const x = drawingArea.value.left + segmentWidth * i + segmentWidth / 2;
+ const x = drawingArea.value?.left + segmentWidth * i + segmentWidth / 2;
const y1 = alwaysAtZero
- ? zero.value - (zero.value === drawingArea.value.bottom ? 0 : size / 2)
- : drawingArea.value.bottom;
+ ? zero.value - (zero.value === drawingArea.value?.bottom ? 0 : size / 2)
+ : drawingArea.value?.bottom;
const y2 = alwaysAtZero
- ? zero.value + (size / (zero.value === drawingArea.value.bottom ? 1 : 2))
- : drawingArea.value.bottom + size;
+ ? zero.value + (size / (zero.value === drawingArea.value?.bottom ? 1 : 2))
+ : drawingArea.value?.bottom + size;
return `M${x},${y1} L${x},${y2}`;
})
@@ -1005,14 +1019,14 @@ function ratioToMax(v) {
const zero = computed(() => {
if (isNaN(ratioToMax(relativeZero.value))) {
- return drawingArea.value.bottom;
+ return drawingArea.value?.bottom;
} else {
- return drawingArea.value.bottom - (drawingArea.value.height * ratioToMax(relativeZero.value));
+ return drawingArea.value?.bottom - (drawingArea.value.height * ratioToMax(relativeZero.value));
}
});
function calcRectHeight(plot) {
- const zeroForPositiveValuesOnly = ![null, undefined].includes(FINAL_CONFIG.value.chart.grid.labels.yAxis.scaleMin) && FINAL_CONFIG.value.chart.grid.labels.yAxis.scaleMin > 0 && min.value >= 0 ? drawingArea.value.bottom : zero.value;
+ const zeroForPositiveValuesOnly = ![null, undefined].includes(FINAL_CONFIG.value.chart.grid.labels.yAxis.scaleMin) && FINAL_CONFIG.value.chart.grid.labels.yAxis.scaleMin > 0 && min.value >= 0 ? drawingArea.value?.bottom : zero.value;
if (plot.value >= 0) {
return checkNaN(zeroForPositiveValuesOnly - plot.y <= 0 ? 0.00001 : zeroForPositiveValuesOnly - plot.y);
@@ -1056,7 +1070,7 @@ function calcRectX(plot) {
function calcRectY(plot) {
if (plot.value >= 0) return plot.y;
- return [null, undefined, NaN, Infinity, -Infinity].includes(zero.value) ? drawingArea.bottom.value : zero.value;
+ return [null, undefined, NaN, Infinity, -Infinity].includes(zero.value) ? drawingArea?.bottom.value : zero.value;
}
function calcIndividualRectY(plot) {
@@ -1090,8 +1104,8 @@ function clientToSvgCoords(evt) {
const drawnH = vb.height * scale;
const offsetX = (rect.width - drawnW) / 2;
const offsetY = (rect.height - drawnH) / 2;
- const x = (evt.clientX - rect.left - offsetX) / scale + vb.x;
- const y = (evt.clientY - rect.top - offsetY) / scale + vb.y;
+ const x = (evt.clientX - rect?.left - offsetX) / scale + vb.x;
+ const y = (evt.clientY - rect?.top - offsetY) / scale + vb.y;
return { x, y, ok: true };
}
@@ -1233,6 +1247,39 @@ function segregate(legendItem) {
segregateStep.value += 1;
}
+function validSeriesToToggle(name) {
+ if (!absoluteDataset.value.length) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn('VueUiXy - There are no series to show.');
+ }
+ return null;
+ }
+ const dp = absoluteDataset.value.find(d => d.name === name);
+ if (!dp) {
+ if (FINAL_CONFIG.value.debug) {
+ console.warn(`VueUiXy - Series name not found "${name}"`);
+ }
+ return null;
+ }
+ return dp;
+}
+
+function showSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (segregatedSeries.value.includes(dp.id)) {
+ segregate({ id : dp.id });
+ }
+}
+
+function hideSeries(name) {
+ const dp = validSeriesToToggle(name);
+ if (dp === null) return;
+ if (!segregatedSeries.value.includes(dp.id)) {
+ segregate({ id: dp.id });
+ }
+}
+
const chartAriaLabel = computed(() => {
const titleText = FINAL_CONFIG.value.chart.title.text || 'Chart visualization';
const subtitleText = FINAL_CONFIG.value.chart.title.subtitle.text || '';
@@ -1442,24 +1489,24 @@ const annotationsY = computed(() => {
const textWidth = ctx.measureText(label.text).width;
const textHeight = label.fontSize;
- const xText = (label.position === 'start' ? left + label.padding.left : right - label.padding.right) + label.offsetX;
+ const xText = (label.position === 'start' ? left + label.padding?.left : right - label.padding?.right) + label.offsetX;
const baselineY = (yTop != null && yBottom != null)
? Math.min(yTop, yBottom)
: (yTop != null ? yTop : yBottom);
- const yText = baselineY - (label.fontSize / 3) + label.offsetY - label.padding.top;
+ const yText = baselineY - (label.fontSize / 3) + label.offsetY - label.padding?.top;
let rectX;
if (label.textAnchor === 'middle') {
- rectX = xText - (textWidth / 2) - label.padding.left;
+ rectX = xText - (textWidth / 2) - label.padding?.left;
} else if (label.textAnchor === 'end') {
- rectX = xText - textWidth - label.padding.right;
+ rectX = xText - textWidth - label.padding?.right;
} else {
- rectX = xText - label.padding.left;
+ rectX = xText - label.padding?.left;
}
- const rectY = yText - (textHeight * 0.75) - label.padding.top;
+ const rectY = yText - (textHeight * 0.75) - label.padding?.top;
const show = ![yTop, yBottom, rectY].includes(NaN);
return {
@@ -1476,8 +1523,8 @@ const annotationsY = computed(() => {
_box: {
x: rectX,
y: rectY,
- width: textWidth + label.padding.left + label.padding.right,
- height: textHeight + label.padding.top + label.padding.bottom,
+ width: textWidth + label.padding?.left + label.padding?.right,
+ height: textHeight + label.padding?.top + label.padding?.bottom,
fill: label.backgroundColor,
stroke: label.border.stroke,
rx: label.border.rx,
@@ -1548,16 +1595,16 @@ const barSet = computed(() => {
const yOffset = stacked ? usableHeight * flippedLowerRatio + gap * flippedIdx : 0;
const individualHeight = stacked ? usableHeight * datapoint.stackRatio : drawingArea.value.height;
- const zeroPosition = drawingArea.value.bottom - yOffset - ((individualHeight) * individualZero / individualMax);
- const autoScaleZeroPosition = drawingArea.value.bottom - yOffset - (individualHeight * autoScaleZero / autoScaleMax);
+ const zeroPosition = drawingArea.value?.bottom - yOffset - ((individualHeight) * individualZero / individualMax);
+ const autoScaleZeroPosition = drawingArea.value?.bottom - yOffset - (individualHeight * autoScaleZero / autoScaleMax);
const barLen = absoluteDataset.value.filter(ds => ds.type === 'bar').filter(s => !segregatedSeries.value.includes(s.id)).length;
const plots = datapoint.series.map((plot, j) => {
const yRatio = mutableConfig.value.useIndividualScale ? ((datapoint.absoluteValues[j] + individualZero) / individualMax) : ratioToMax(plot)
const x = mutableConfig.value.useIndividualScale && mutableConfig.value.isStacked
- ? drawingArea.value.left + (drawingArea.value.width / maxSeries.value * j)
- : drawingArea.value.left
+ ? drawingArea.value?.left + (drawingArea.value.width / maxSeries.value * j)
+ : drawingArea.value?.left
+ (slot.value.bar * i)
+ (slot.value.bar * j * barLen)
- (barSlot.value / 2)
@@ -1568,7 +1615,7 @@ const barSet = computed(() => {
yOffset: checkNaN(yOffset),
individualHeight: checkNaN(individualHeight),
x: checkNaN(x),
- y: drawingArea.value.bottom - yOffset - (individualHeight * yRatio),
+ y: drawingArea.value?.bottom - yOffset - (individualHeight * yRatio),
value: datapoint.absoluteValues[j],
zeroPosition: checkNaN(zeroPosition),
individualMax: checkNaN(individualMax),
@@ -1586,13 +1633,13 @@ const barSet = computed(() => {
const autoScalePlots = datapoint.series.map((_, j) => {
const x = mutableConfig.value.useIndividualScale && mutableConfig.value.isStacked
- ? drawingArea.value.left + (drawingArea.value.width / maxSeries.value * j)
- : (drawingArea.value.left - slot.value.bar / 2 + slot.value.bar * i) + (slot.value.bar * j * absoluteDataset.value.filter(ds => ds.type === 'bar').filter(s => !segregatedSeries.value.includes(s.id)).length);
+ ? drawingArea.value?.left + (drawingArea.value.width / maxSeries.value * j)
+ : (drawingArea.value?.left - slot.value.bar / 2 + slot.value.bar * i) + (slot.value.bar * j * absoluteDataset.value.filter(ds => ds.type === 'bar').filter(s => !segregatedSeries.value.includes(s.id)).length);
return {
yOffset: checkNaN(yOffset),
individualHeight: checkNaN(individualHeight),
x: checkNaN(x),
- y: checkNaN(drawingArea.value.bottom - checkNaN(yOffset) - ((checkNaN(individualHeight) * autoScaleRatiosToNiceScale[j]) || 0)),
+ y: checkNaN(drawingArea.value?.bottom - checkNaN(yOffset) - ((checkNaN(individualHeight) * autoScaleRatiosToNiceScale[j]) || 0)),
value: datapoint.absoluteValues[j],
zeroPosition: checkNaN(zeroPosition),
individualMax: checkNaN(individualMax),
@@ -1699,9 +1746,9 @@ const lineSet = computed(() => {
const yOffset = stacked ? usableHeight * flippedLowerRatio + gap * flippedIdx : 0;
const individualHeight = stacked ? usableHeight * datapoint.stackRatio : drawingArea.value.height;
- const zeroPosition = drawingArea.value.bottom - yOffset - ((individualHeight) * individualZero / individualMax);
+ const zeroPosition = drawingArea.value?.bottom - yOffset - ((individualHeight) * individualZero / individualMax);
- const autoScaleZeroPosition = drawingArea.value.bottom - yOffset - (individualHeight * autoScaleZero / autoScaleMax);
+ const autoScaleZeroPosition = drawingArea.value?.bottom - yOffset - (individualHeight * autoScaleZero / autoScaleMax);
const plots = datapoint.series.map((plot, j) => {
const yRatio = mutableConfig.value.useIndividualScale
@@ -1709,8 +1756,8 @@ const lineSet = computed(() => {
: ratioToMax(plot)
return {
- x: checkNaN((drawingArea.value.left + (slot.value.line / 2)) + (slot.value.line * j)),
- y: checkNaN(drawingArea.value.bottom - yOffset - (individualHeight * yRatio)),
+ x: checkNaN((drawingArea.value?.left + (slot.value.line / 2)) + (slot.value.line * j)),
+ y: checkNaN(drawingArea.value?.bottom - yOffset - (individualHeight * yRatio)),
value: datapoint.absoluteValues[j],
comment: datapoint.comments ? datapoint.comments.slice(slicer.value.start, slicer.value.end)[j] || '' : ''
}
@@ -1727,14 +1774,14 @@ const lineSet = computed(() => {
const autoScalePlots = datapoint.series.map((_, j) => {
if (![undefined, null].includes(datapoint.absoluteValues[j])) {
return {
- x: checkNaN((drawingArea.value.left + (slot.value.line / 2)) + (slot.value.line * j)),
- y: checkNaN(drawingArea.value.bottom - yOffset - ((individualHeight * autoScaleRatiosToNiceScale[j]) || 0)),
+ x: checkNaN((drawingArea.value?.left + (slot.value.line / 2)) + (slot.value.line * j)),
+ y: checkNaN(drawingArea.value?.bottom - yOffset - ((individualHeight * autoScaleRatiosToNiceScale[j]) || 0)),
value: datapoint.absoluteValues[j],
comment: datapoint.comments ? datapoint.comments.slice(slicer.value.start, slicer.value.end)[j] || '' : ''
}
} else {
return {
- x: checkNaN((drawingArea.value.left + (slot.value.line / 2)) + (slot.value.line * j)),
+ x: checkNaN((drawingArea.value?.left + (slot.value.line / 2)) + (slot.value.line * j)),
y: zeroPosition,
value: datapoint.absoluteValues[j],
comment: datapoint.comments ? datapoint.comments.slice(slicer.value.start, slicer.value.end)[j] || '' : ''
@@ -1794,7 +1841,7 @@ const lineSet = computed(() => {
scaleGroups.value[datapoint.scaleLabel].unique = activeSeriesWithStackRatios.value.filter(el => el.scaleLabel === datapoint.scaleLabel).length === 1
const areaZeroPosition = mutableConfig.value.useIndividualScale ? datapoint.autoScaling ? autoScaleZeroPosition : zeroPosition : zero.value;
- const adustedAreaZeroPosition = Math.max(Math.max(datapoint.autoScaling ? autoScaleZeroPosition : (scaleYLabels.at(-1) ? scaleYLabels.at(-1).y : 0), drawingArea.value.top), areaZeroPosition);
+ const adustedAreaZeroPosition = Math.max(Math.max(datapoint.autoScaling ? autoScaleZeroPosition : (scaleYLabels.at(-1) ? scaleYLabels.at(-1).y : 0), drawingArea.value?.top), areaZeroPosition);
return {
...datapoint,
@@ -1888,14 +1935,14 @@ const plotSet = computed(() => {
const yOffset = stacked ? usableHeight * flippedLowerRatio + gap * flippedIdx : 0;
const individualHeight = stacked ? usableHeight * datapoint.stackRatio : drawingArea.value.height;
- const zeroPosition = drawingArea.value.bottom - yOffset - ((individualHeight) * individualZero / individualMax);
- const autoScaleZeroPosition = drawingArea.value.bottom - yOffset - (individualHeight * autoScaleZero / autoScaleMax);
+ const zeroPosition = drawingArea.value?.bottom - yOffset - ((individualHeight) * individualZero / individualMax);
+ const autoScaleZeroPosition = drawingArea.value?.bottom - yOffset - (individualHeight * autoScaleZero / autoScaleMax);
const plots = datapoint.series.map((plot, j) => {
const yRatio = mutableConfig.value.useIndividualScale ? ((datapoint.absoluteValues[j] + Math.abs(individualZero)) / individualMax) : ratioToMax(plot)
return {
- x: checkNaN((drawingArea.value.left + (slot.value.plot / 2)) + (slot.value.plot * j)),
- y: checkNaN(drawingArea.value.bottom - yOffset - (individualHeight * yRatio)),
+ x: checkNaN((drawingArea.value?.left + (slot.value.plot / 2)) + (slot.value.plot * j)),
+ y: checkNaN(drawingArea.value?.bottom - yOffset - (individualHeight * yRatio)),
value: datapoint.absoluteValues[j],
comment: datapoint.comments ? datapoint.comments.slice(slicer.value.start, slicer.value.end)[j] || '' : ''
}
@@ -1911,8 +1958,8 @@ const plotSet = computed(() => {
const autoScalePlots = datapoint.series.map((_, j) => {
return {
- x: checkNaN((drawingArea.value.left + (slot.value.plot / 2)) + (slot.value.plot * j)),
- y: checkNaN(drawingArea.value.bottom - yOffset - ((individualHeight * autoScaleRatiosToNiceScale[j]) || 0)),
+ x: checkNaN((drawingArea.value?.left + (slot.value.plot / 2)) + (slot.value.plot * j)),
+ y: checkNaN(drawingArea.value?.bottom - yOffset - ((individualHeight * autoScaleRatiosToNiceScale[j]) || 0)),
value: datapoint.absoluteValues[j],
comment: datapoint.comments ? datapoint.comments.slice(slicer.value.start, slicer.value.end)[j] || '' : ''
}
@@ -2020,7 +2067,7 @@ const allScales = computed(() => {
return _source.flatMap((el, i) => {
let x = 0;
- x = mutableConfig.value.isStacked ? drawingArea.value.left : drawingArea.value.left / len * (i + 1);
+ x = mutableConfig.value.isStacked ? drawingArea.value?.left : drawingArea.value?.left / len * (i + 1);
const name = (mutableConfig.value.useIndividualScale && !mutableConfig.value.isStacked) ? el.unique ? el.name : el.groupName : el.name
@@ -2657,10 +2704,10 @@ function timeTagX() {
const W_FO = 200;
const sectionsX = Math.max(1, maxSeries.value);
const sectionX = drawingArea.value.width / sectionsX;
- const centerX = drawingArea.value.left + activeIndex.value * sectionX + sectionX / 2;
+ const centerX = drawingArea.value?.left + activeIndex.value * sectionX + sectionX / 2;
const desiredX = centerX - w / 2 - (W_FO - w) / 2;
- const minX = drawingArea.value.left - (W_FO - w) / 2;
- const _maxX = drawingArea.value.right - (W_FO + w) / 2;
+ const minX = drawingArea.value?.left - (W_FO - w) / 2;
+ const _maxX = drawingArea.value?.right - (W_FO + w) / 2;
const clamped = Math.max(minX, Math.min(desiredX, _maxX));
return checkNaN(clamped);
}
@@ -2909,6 +2956,8 @@ defineExpose({
generateImage,
generateSvg,
generateCsv,
+ hideSeries,
+ showSeries,
toggleStack,
toggleTable,
toggleLabels,
@@ -2926,7 +2975,26 @@ defineExpose({
@mouseenter="() => setUserOptionsVisibility(true)" @mouseleave="() => setUserOptionsVisibility(false)" @click="onSvgClick">
+ :active="isAnnotator" @close="toggleAnnotator">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2986,14 +3054,17 @@ defineExpose({
+
+
+
-
-
+
+
@@ -3026,7 +3097,7 @@ defineExpose({
@@ -3066,14 +3137,14 @@ defineExpose({
-
-
@@ -3151,16 +3222,16 @@ defineExpose({
transition: 'none',
opacity: (oneArea.from + i >= slicer.start && (oneArea.from + i <= slicer.end - 1)) ? 1 : 0
}"
- :x="drawingArea.left + (drawingArea.width / maxSeries) * ((oneArea.from + i) - slicer.start)"
- :y="drawingArea.top" :height="drawingArea.height < 0 ? 10 : drawingArea.height"
+ :x="drawingArea?.left + (drawingArea.width / maxSeries) * ((oneArea.from + i) - slicer.start)"
+ :y="drawingArea?.top" :height="drawingArea.height < 0 ? 10 : drawingArea.height"
:width="drawingArea.width / maxSeries < 0 ? 0.00001 : drawingArea.width / maxSeries"
:fill="setOpacity(oneArea.color, oneArea.opacity)" />
-
@@ -3243,9 +3314,9 @@ defineExpose({
@@ -3281,7 +3352,7 @@ defineExpose({
:fill="el.color"
:font-size="fontSizes.dataLabels * 0.8"
text-anchor="middle"
- :transform="`translate(${el.x - ((fontSizes.dataLabels * 0.8) / 2) + xPadding}, ${mutableConfig.isStacked ? drawingArea.bottom - el.yOffset - (el.individualHeight / 2) : drawingArea.top + drawingArea.height / 2}) rotate(-90)`">
+ :transform="`translate(${el.x - ((fontSizes.dataLabels * 0.8) / 2) + xPadding}, ${mutableConfig.isStacked ? drawingArea?.bottom - el.yOffset - (el.individualHeight / 2) : drawingArea?.top + drawingArea.height / 2}) rotate(-90)`">
{{ el.name }} {{ el.scaleLabel && el.unique && el.scaleLabel !== el.id ? `-
${el.scaleLabel}` : '' }}
@@ -3318,8 +3389,8 @@ defineExpose({
@@ -3581,7 +3652,7 @@ defineExpose({
@@ -3660,7 +3731,7 @@ defineExpose({
@@ -3810,7 +3881,7 @@ defineExpose({
{{ FINAL_CONFIG.chart.grid.labels.axis.yLabel }}
@@ -3840,11 +3911,11 @@ defineExpose({
0 ? 'start' : FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation < 0 ? 'end' : 'middle'"
:font-size="fontSizes.xAxis"
:fill="FINAL_CONFIG.chart.grid.labels.xAxisLabels.color"
- :transform="`translate(${drawingArea.left + (drawingArea.width / maxSeries) * i + (drawingArea.width / maxSeries / 2)}, ${drawingArea.bottom + fontSizes.xAxis * 1.5}), rotate(${FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation})`"
+ :transform="`translate(${drawingArea?.left + (drawingArea.width / maxSeries) * i + (drawingArea.width / maxSeries / 2)}, ${drawingArea?.bottom + fontSizes.xAxis * 1.5}), rotate(${FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation})`"
:style="{
cursor: usesSelectTimeLabelEvent() ? 'pointer' : 'default'
}" @click="() => selectTimeLabel(label, i)">
@@ -3875,7 +3946,7 @@ defineExpose({
:text-anchor="FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation > 0 ? 'start' : FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation < 0 ? 'end' : 'middle'"
:font-size="fontSizes.xAxis"
:fill="FINAL_CONFIG.chart.grid.labels.xAxisLabels.color"
- :transform="`translate(${drawingArea.left + (drawingArea.width / maxSeries) * i + (drawingArea.width / maxSeries / 2)}, ${drawingArea.bottom + fontSizes.xAxis * 1.5}), rotate(${FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation})`"
+ :transform="`translate(${drawingArea?.left + (drawingArea.width / maxSeries) * i + (drawingArea.width / maxSeries / 2)}, ${drawingArea?.bottom + fontSizes.xAxis * 1.5}), rotate(${FINAL_CONFIG.chart.grid.labels.xAxisLabels.rotation})`"
:style="{
cursor: usesSelectTimeLabelEvent() ? 'pointer' : 'default'
}" v-html="createTSpansFromLineBreaksOnX({
@@ -3929,7 +4000,7 @@ defineExpose({
style="pointer-events:none">
+ :y="drawingArea?.bottom" width="200" height="40" style="overflow: visible !important;">
@@ -3953,7 +4024,11 @@ defineExpose({
:data-end="slicer.end"
/>
-
+
@@ -3970,18 +4045,18 @@ defineExpose({
position: 'fixed',
top: placeXYTag({
svgElement: svgRef,
- x: drawingArea.right + FINAL_CONFIG.line.tag.fontSize / 1.5,
+ x: drawingArea?.right + FINAL_CONFIG.line.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_right_line`],
position: 'right'
- }).top + 'px',
+ })?.top + 'px',
left: placeXYTag({
svgElement: svgRef,
- x: drawingArea.right + FINAL_CONFIG.line.tag.fontSize / 1.5,
+ x: drawingArea?.right + FINAL_CONFIG.line.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_right_line`],
position: 'right'
- }).left + 'px',
+ })?.left + 'px',
height: 'fit-content',
width: 'fit-content',
background: serie.color,
@@ -4010,18 +4085,18 @@ defineExpose({
position: 'fixed',
top: placeXYTag({
svgElement: svgRef,
- x: drawingArea.left - FINAL_CONFIG.line.tag.fontSize / 1.5,
+ x: drawingArea?.left - FINAL_CONFIG.line.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_left_line`],
position: 'left'
- }).top + 'px',
+ })?.top + 'px',
left: placeXYTag({
svgElement: svgRef,
- x: drawingArea.left - FINAL_CONFIG.line.tag.fontSize / 1.5,
+ x: drawingArea?.left - FINAL_CONFIG.line.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_left_line`],
position: 'left'
- }).left + 'px',
+ })?.left + 'px',
height: 'fit-content',
width: 'fit-content',
background: serie.color,
@@ -4056,18 +4131,18 @@ defineExpose({
position: 'fixed',
top: placeXYTag({
svgElement: svgRef,
- x: drawingArea.right + FINAL_CONFIG.plot.tag.fontSize / 1.5,
+ x: drawingArea?.right + FINAL_CONFIG.plot.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_right_plot`],
position: 'right'
- }).top + 'px',
+ })?.top + 'px',
left: placeXYTag({
svgElement: svgRef,
- x: drawingArea.right + FINAL_CONFIG.plot.tag.fontSize / 1.5,
+ x: drawingArea?.right + FINAL_CONFIG.plot.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_right_plot`],
position: 'right'
- }).left + 'px',
+ })?.left + 'px',
height: 'fit-content',
width: 'fit-content',
background: serie.color,
@@ -4096,18 +4171,18 @@ defineExpose({
position: 'fixed',
top: placeXYTag({
svgElement: svgRef,
- x: drawingArea.left - FINAL_CONFIG.plot.tag.fontSize / 1.5,
+ x: drawingArea?.left - FINAL_CONFIG.plot.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_left_plot`],
position: 'left'
- }).top + 'px',
+ })?.top + 'px',
left: placeXYTag({
svgElement: svgRef,
- x: drawingArea.left - FINAL_CONFIG.plot.tag.fontSize / 1.5,
+ x: drawingArea?.left - FINAL_CONFIG.plot.tag.fontSize / 1.5,
y: plot.y,
element: tagRefs[`${i}_${j}_left_plot`],
position: 'left'
- }).left + 'px',
+ })?.left + 'px',
height: 'fit-content',
width: 'fit-content',
background: serie.color,
diff --git a/src/entries/vue-ui-horizontal-bar.js b/src/entries/vue-ui-horizontal-bar.js
index ead4ea8b..44b64156 100644
--- a/src/entries/vue-ui-horizontal-bar.js
+++ b/src/entries/vue-ui-horizontal-bar.js
@@ -1,2 +1,2 @@
-export { default as VueUiHorizontalBar } from "../components/vue-ui-vertical-bar.vue";
-export { default } from "../components/vue-ui-vertical-bar.vue";
\ No newline at end of file
+export { default as VueUiHorizontalBar } from "../components/vue-ui-horizontal-bar.vue";
+export { default } from "../components/vue-ui-horizontal-bar.vue";
\ No newline at end of file
diff --git a/src/entries/vue-ui-stackline.js b/src/entries/vue-ui-stackline.js
new file mode 100644
index 00000000..3f828b17
--- /dev/null
+++ b/src/entries/vue-ui-stackline.js
@@ -0,0 +1,2 @@
+export { default as VueUiStackline } from "../components/vue-ui-stackline.vue";
+export { default } from "../components/vue-ui-stackline.vue";
\ No newline at end of file
diff --git a/src/entries/vue-ui-vertical-bar.js b/src/entries/vue-ui-vertical-bar.js
index add9b205..f9b0c84f 100644
--- a/src/entries/vue-ui-vertical-bar.js
+++ b/src/entries/vue-ui-vertical-bar.js
@@ -1,2 +1,3 @@
-export { default as VueUiVerticalBar } from "../components/vue-ui-vertical-bar.vue";
-export { default } from "../components/vue-ui-vertical-bar.vue";
\ No newline at end of file
+// Legacy support for old vertical-bar faulty naming
+export { default as VueUiVerticalBar } from "../components/vue-ui-horizontal-bar.vue";
+export { default } from "../components/vue-ui-horizontal-bar.vue";
\ No newline at end of file
diff --git a/src/getThemeConfig.js b/src/getThemeConfig.js
index 8ee6f3f2..8ff99ea1 100644
--- a/src/getThemeConfig.js
+++ b/src/getThemeConfig.js
@@ -1,5 +1,55 @@
-import themes from "./themes.json";
+const _globLoaders = import.meta.glob('./themes/*.json', { import: 'default' });
-export default function getThemeConfig(type) {
- return themes[type]
-}
\ No newline at end of file
+const THEME_LOADERS = Object.fromEntries(
+ Object.entries(_globLoaders).map(([path, load]) => {
+ const m = path.match(/\/themes\/(.+)\.json$/);
+ const type = m ? m[1] : path;
+ return [type, load];
+ })
+);
+
+const _cache = new Map();
+
+let _loader = async (type) => {
+ const load = THEME_LOADERS[type];
+ if (!load) {
+ const err = new Error('ENOENT');
+ err.code = 'ENOENT';
+ throw err;
+ }
+ return await load();
+};
+
+async function getThemeConfig(type) {
+ if (!type) return null;
+ if (_cache.has(type)) return _cache.get(type);
+ try {
+ const theme = await _loader(type);
+ _cache.set(type, theme);
+ return theme;
+ } catch (e) {
+ console.warn(`[getThemeConfig] Missing theme file: ${type}.json`, e);
+ return null;
+ }
+}
+
+export default getThemeConfig;
+export { getThemeConfig };
+
+export function getThemeConfigSync(type) {
+ if (!type) return null;
+ return _cache.get(type) ?? null;
+}
+
+export async function preloadTheme(type) {
+ return await getThemeConfig(type);
+}
+export async function preloadThemes(types = []) {
+ return Promise.all(types.map(getThemeConfig));
+}
+
+export const __testing = {
+ clearCache: () => _cache.clear(),
+ cacheSize: () => _cache.size,
+ setLoader: (fn) => { _loader = fn; },
+};
diff --git a/src/index.js b/src/index.js
index 486084b9..b9c80580 100755
--- a/src/index.js
+++ b/src/index.js
@@ -47,8 +47,8 @@ export { default as VueUiThermometer } from "./components/vue-ui-thermometer.vue
export { default as VueUiTimer } from "./components/vue-ui-timer.vue";
export { default as VueUiTiremarks } from "./components/vue-ui-tiremarks.vue";
export { default as VueUiTreemap } from "./components/vue-ui-treemap.vue";
-export { default as VueUiVerticalBar } from "./components/vue-ui-vertical-bar.vue";
-export { default as VueUiHorizontalBar } from "./components/vue-ui-vertical-bar.vue";
+export { default as VueUiVerticalBar } from "./components/vue-ui-horizontal-bar.vue"; // Legacy support
+export { default as VueUiHorizontalBar } from "./components/vue-ui-horizontal-bar.vue";
export { default as VueUiWaffle } from "./components/vue-ui-waffle.vue";
export { default as VueUiWheel } from "./components/vue-ui-wheel.vue";
export { default as VueUiWordCloud } from "./components/vue-ui-word-cloud.vue";
@@ -56,6 +56,7 @@ export { default as VueUiXyCanvas } from "./components/vue-ui-xy-canvas.vue";
export { default as VueUiCarouselTable } from "./components/vue-ui-carousel-table.vue";
export { default as VueUiGizmo } from "./components/vue-ui-gizmo.vue";
export { default as VueUiStackbar } from "./components/vue-ui-stackbar.vue";
+export { default as VueUiStackline } from "./components/vue-ui-stackline.vue";
export { default as VueUiBullet } from "./components/vue-ui-bullet.vue";
export { default as VueUiFunnel } from "./components/vue-ui-funnel.vue";
export { default as VueUiHistoryPlot } from "./components/vue-ui-history-plot.vue";
diff --git a/src/legacy/LEGACY.md b/src/legacy/LEGACY.md
new file mode 100644
index 00000000..9a78ca20
--- /dev/null
+++ b/src/legacy/LEGACY.md
@@ -0,0 +1,6 @@
+Components in this directory are there for archive purposes.
+
+## VueUiVerticalBar
+
+- Faulty dimension calculation logic, leading to impossible resolutions for responsive mode, and causing overflows and weird resizing on serie segregations
+- Legacy naming
diff --git a/src/components/vue-ui-vertical-bar.vue b/src/legacy/vue-ui-vertical-bar.vue
similarity index 95%
rename from src/components/vue-ui-vertical-bar.vue
rename to src/legacy/vue-ui-vertical-bar.vue
index 4a86f2c6..6116ac49 100644
--- a/src/components/vue-ui-vertical-bar.vue
+++ b/src/legacy/vue-ui-vertical-bar.vue
@@ -1,4 +1,5 @@