From d0ab36799f13d449fa4a31260205bb3813a9ad16 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Wed, 9 Apr 2025 17:37:27 +0530 Subject: [PATCH] Add HorizontalBarChart and LineChart components; update package dependencies --- index.html | 2 - package-lock.json | 96 +++++++++++++- package.json | 2 + src/components/Charts/HorizontalBarChart.jsx | 130 +++++++++++++++++++ src/components/Charts/LineChart.jsx | 103 +++++++++++++++ 5 files changed, 327 insertions(+), 6 deletions(-) create mode 100644 src/components/Charts/HorizontalBarChart.jsx create mode 100644 src/components/Charts/LineChart.jsx diff --git a/index.html b/index.html index f6530280..40dbda9b 100644 --- a/index.html +++ b/index.html @@ -27,7 +27,6 @@ - @@ -83,7 +82,6 @@ - diff --git a/package-lock.json b/package-lock.json index adfa6823..58ea533a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@reduxjs/toolkit": "^2.5.0", "@types/web": "^0.0.216", "@vitejs/plugin-react": "^4.3.4", + "apexcharts": "^4.5.0", "axios": "^1.7.9", "axios-retry": "^4.5.0", "dotenv": "^16.4.7", @@ -22,6 +23,7 @@ "moment": "^2.30.1", "perfect-scrollbar": "^1.5.5", "react": "^18.2.0", + "react-apexcharts": "^1.7.0", "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", "react-redux": "^9.2.0", @@ -1116,6 +1118,62 @@ "win32" ] }, + "node_modules/@svgdotjs/svg.draggable.js": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz", + "integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==", + "license": "MIT", + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, + "node_modules/@svgdotjs/svg.filter.js": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.filter.js/-/svg.filter.js-3.0.9.tgz", + "integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.js": "^3.2.4" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@svgdotjs/svg.js": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.4.tgz", + "integrity": "sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Fuzzyma" + } + }, + "node_modules/@svgdotjs/svg.resize.js": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.resize.js/-/svg.resize.js-2.0.5.tgz", + "integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.select.js": "^4.0.1" + } + }, + "node_modules/@svgdotjs/svg.select.js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.select.js/-/svg.select.js-4.0.2.tgz", + "integrity": "sha512-5gWdrvoQX3keo03SCmgaBbD+kFftq0F/f2bzCbNnpkkvW6tk4rl4MakORzFuNjvXPWwB4az9GwuvVxQVnjaK2g==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, "node_modules/@swc/core": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.1.tgz", @@ -1656,6 +1714,12 @@ "license": "Apache-2.0", "peer": true }, + "node_modules/@yr/monotone-cubic-spline": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", + "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==", + "license": "MIT" + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -1758,6 +1822,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/apexcharts": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-4.5.0.tgz", + "integrity": "sha512-E7ZkrVqPNBUWy/Rmg8DEIqHNBmElzICE/oxOX5Ekvs2ICQUOK/VkEkMH09JGJu+O/EA0NL31hxlmF+wrwrSLaQ==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.draggable.js": "^3.0.4", + "@svgdotjs/svg.filter.js": "^3.0.8", + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.resize.js": "^2.0.2", + "@svgdotjs/svg.select.js": "^4.0.1", + "@yr/monotone-cubic-spline": "^1.0.3" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4000,7 +4078,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4261,7 +4338,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4323,6 +4399,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-apexcharts": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.7.0.tgz", + "integrity": "sha512-03oScKJyNLRf0Oe+ihJxFZliBQM9vW3UWwomVn4YVRTN1jsIR58dLWt0v1sb8RwJVHDMbeHiKQueM0KGpn7nOA==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "apexcharts": ">=4.0.0", + "react": ">=0.13" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -4354,8 +4443,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-redux": { "version": "9.2.0", diff --git a/package.json b/package.json index ee6a4a1b..6009a61d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@reduxjs/toolkit": "^2.5.0", "@types/web": "^0.0.216", "@vitejs/plugin-react": "^4.3.4", + "apexcharts": "^4.5.0", "axios": "^1.7.9", "axios-retry": "^4.5.0", "dotenv": "^16.4.7", @@ -25,6 +26,7 @@ "moment": "^2.30.1", "perfect-scrollbar": "^1.5.5", "react": "^18.2.0", + "react-apexcharts": "^1.7.0", "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", "react-redux": "^9.2.0", diff --git a/src/components/Charts/HorizontalBarChart.jsx b/src/components/Charts/HorizontalBarChart.jsx new file mode 100644 index 00000000..c1165b96 --- /dev/null +++ b/src/components/Charts/HorizontalBarChart.jsx @@ -0,0 +1,130 @@ +import React from "react"; +import ReactApexChart from "react-apexcharts"; +import PropTypes from "prop-types"; + +const HorizontalBarChart = ({ + seriesData = [], + categories = [], + colors = [ + "#1E90FF", // Dodger Blue - Primary + "#00BFFF", // Deep Sky Blue - Info + "#9370DB", // Medium Purple - Success (replacing Lime Green) + "#6A0DAD", // Amethyst Purple - On Route (replacing Forest Green) + "#A9A9A9", // Dark Gray - Neutral + "#6A5ACD", // Slate Blue - Secondary + "#FFA500", // Orange - Warning + "#FF4500", // Orange Red - Danger + "#20B2AA", // Light Sea Green - Late + "#708090", // Slate Gray - Muted + ], + + +}) => { + // Guard clause for invalid or incomplete data + const hasValidData = + Array.isArray(seriesData) && + seriesData.length > 0 && + Array.isArray(categories) && + categories.length === seriesData.length; + + if (!hasValidData) { + return
No data to display
; + } + + const chartOptions = { + + chart: { + type: "bar", + height: 380, + toolbar: { + show: false, // This removes the menu + }, + }, + grid: { + show: false + }, + plotOptions: { + bar: { + barHeight: "80%", + distributed: true, + horizontal: true, + dataLabels: { + position: "center", + }, + }, + }, + colors, + dataLabels: { + enabled: true, + textAnchor: "start", + style: { + colors: ["#000"], // Switch to black for better visibility + }, + formatter: function (val, opt) { + return `${opt.w.globals.labels[opt.dataPointIndex]}: ${val}`; + }, + offsetX: 10, // Push label slightly to the right + dropShadow: { + enabled: false, + }, + }, + + stroke: { + width: 1, + colors: ["#fff"], + }, + xaxis: { + categories, + axisBorder: { + show: false, + }, + axisTicks: { + show: false, + }, + labels: { + show: false, + }, + }, + yaxis: { + labels: { + show: false, + }, + axisBorder: { + show: false, + }, + axisTicks: { + show: false, + }, + }, + tooltip: { + theme: "dark", + x: { + show: false, + }, + y: { + title: { + formatter: () => "", + }, + }, + }, + }; + + return ( +
+ +
+ ); +}; + +HorizontalBarChart.propTypes = { + seriesData: PropTypes.arrayOf(PropTypes.number), + categories: PropTypes.arrayOf(PropTypes.string), + colors: PropTypes.arrayOf(PropTypes.string), +}; + +export default HorizontalBarChart; diff --git a/src/components/Charts/LineChart.jsx b/src/components/Charts/LineChart.jsx new file mode 100644 index 00000000..3008e473 --- /dev/null +++ b/src/components/Charts/LineChart.jsx @@ -0,0 +1,103 @@ +import React from "react"; +import ReactApexChart from "react-apexcharts"; +import PropTypes from "prop-types"; + +const LineChart = ({ + seriesData = [], + categories = [], + colors = ["#1E90FF", "#FF6347"], // default: Dodger Blue & Tomato +}) => { + const hasValidData = + Array.isArray(seriesData) && + seriesData.length > 0 && + Array.isArray(categories) && + categories.length > 0; + + if (!hasValidData) { + return
No data to display
; + } + + const chartOptions = { + chart: { + type: "line", + height: 350, + zoom: { enabled: false }, + toolbar: { show: false }, + background: 'transparent' + }, + colors, + dataLabels: { + enabled: false // Hide value labels on dots + }, + stroke: { + curve: 'straight' + }, + grid: { + show: false, + xaxis: { + lines: { + show: false + } + }, + yaxis: { + lines: { + show: false + } + } + }, + markers: { + size: 5, // Increase dot visibility + strokeWidth: 0, + hover: { + size: 7 + } + }, + xaxis: { + categories, + labels: { show: false }, + axisBorder: { show: false }, + axisTicks: { show: false }, + tooltip: { enabled: false } + }, + yaxis: { + labels: { show: false }, + axisBorder: { show: false }, + axisTicks: { show: false }, + min: 0 + }, + legend: { + show: true // Optional: Hide legend if not needed + }, + tooltip: { + enabled: true // Keep this if you want value on hover + } + }; + + + + + return ( +
+ +
+ ); +}; + +LineChart.propTypes = { + seriesData: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + data: PropTypes.arrayOf(PropTypes.number).isRequired + }) + ), + categories: PropTypes.arrayOf(PropTypes.string), + colors: PropTypes.arrayOf(PropTypes.string), + title: PropTypes.string +}; + +export default LineChart;