sag_components 2.0.0-beta52 → 2.0.0-beta53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +18 -1
- package/dist/index.esm.js +2055 -249
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2055 -247
- package/dist/index.js.map +1 -1
- package/dist/types/components/BrushChart/BrushChart.d.ts +2 -0
- package/dist/types/components/BrushChart/BrushChart.stories.d.ts +8 -0
- package/dist/types/components/BrushChart/BrushChart.style.d.ts +5 -0
- package/dist/types/components/BrushChart/Charts/BarLine.d.ts +2 -0
- package/dist/types/components/BrushChart/Charts/InnerBar.d.ts +1 -0
- package/dist/types/components/BrushChart/Charts/SingleChart.d.ts +2 -0
- package/dist/types/components/BubbleChart/BubbleChart.d.ts +15 -0
- package/dist/types/components/BubbleChart/BubbleChart.stories.d.ts +93 -0
- package/dist/types/components/BubbleChart/BubbleChart.style.d.ts +13 -0
- package/dist/types/components/SegmentedButton/SegmentedButton.d.ts +3 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React$1, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
2
2
|
import styled, { keyframes, css } from 'styled-components';
|
|
3
|
-
import { ResponsiveContainer, PieChart as PieChart$1, Pie, Cell, Tooltip as Tooltip$2, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Bar, LabelList, ReferenceLine, Brush, LineChart, Line, AreaChart as AreaChart$1, Legend, Area } from 'recharts';
|
|
3
|
+
import { ResponsiveContainer, PieChart as PieChart$1, Pie, Cell, Tooltip as Tooltip$2, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Bar, LabelList, ReferenceLine, Brush, LineChart, Line, AreaChart as AreaChart$1, Legend, Area, ScatterChart, ZAxis, Scatter, ComposedChart } from 'recharts';
|
|
4
4
|
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
|
5
5
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
6
6
|
|
|
@@ -1902,7 +1902,7 @@ const ControlsContainer$a = styled.div`
|
|
|
1902
1902
|
box-sizing: border-box;
|
|
1903
1903
|
}
|
|
1904
1904
|
`;
|
|
1905
|
-
const Controls$
|
|
1905
|
+
const Controls$9 = styled.div`
|
|
1906
1906
|
display: flex;
|
|
1907
1907
|
flex-direction: column;
|
|
1908
1908
|
width: 100%;
|
|
@@ -2026,7 +2026,7 @@ const ControlsContainer$9 = styled.div`
|
|
|
2026
2026
|
//border: 1px solid red;
|
|
2027
2027
|
align-items: center;
|
|
2028
2028
|
`;
|
|
2029
|
-
const Controls$
|
|
2029
|
+
const Controls$8 = styled.div`
|
|
2030
2030
|
position: relative;
|
|
2031
2031
|
border-radius: 100px;
|
|
2032
2032
|
width: ${props => props.width.toString().concat('', 'px')};
|
|
@@ -2282,7 +2282,7 @@ const Benchmark = props => {
|
|
|
2282
2282
|
id: "Tooltip",
|
|
2283
2283
|
content: getTooltipText(),
|
|
2284
2284
|
direction: tooltipDirection
|
|
2285
|
-
}, /*#__PURE__*/React$1.createElement(Controls$
|
|
2285
|
+
}, /*#__PURE__*/React$1.createElement(Controls$8, {
|
|
2286
2286
|
id: "ControlsBenchmark",
|
|
2287
2287
|
height: height,
|
|
2288
2288
|
width: width
|
|
@@ -2407,7 +2407,7 @@ const PieChart = props => {
|
|
|
2407
2407
|
}, legendData.length === 0 || legendData.every(item => item.value === undefined || item.value === null) ? /*#__PURE__*/React$1.createElement(NoDataFoundMessage, {
|
|
2408
2408
|
className: "NoDataFoundMessage",
|
|
2409
2409
|
noDataText: noDataText
|
|
2410
|
-
}) : /*#__PURE__*/React$1.createElement(Controls$
|
|
2410
|
+
}) : /*#__PURE__*/React$1.createElement(Controls$9, {
|
|
2411
2411
|
className: "Controls",
|
|
2412
2412
|
height: height,
|
|
2413
2413
|
width: width
|
|
@@ -25147,8 +25147,8 @@ function styleInject(css, ref) {
|
|
|
25147
25147
|
}
|
|
25148
25148
|
}
|
|
25149
25149
|
|
|
25150
|
-
var css_248z = "@keyframes react-loading-skeleton {\n 100% {\n transform: translateX(100%);\n }\n}\n\n.react-loading-skeleton {\n --base-color: #ebebeb;\n --highlight-color: #f5f5f5;\n --animation-duration: 1.5s;\n --animation-direction: normal;\n --pseudo-element-display: block; /* Enable animation */\n\n background-color: var(--base-color);\n\n width: 100%;\n border-radius: 0.25rem;\n display: inline-flex;\n line-height: 1;\n\n position: relative;\n user-select: none;\n overflow: hidden;\n}\n\n.react-loading-skeleton::after {\n content: ' ';\n display: var(--pseudo-element-display);\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background-repeat: no-repeat;\n background-image: var(\n --custom-highlight-background,\n linear-gradient(\n 90deg,\n var(--base-color) 0%,\n var(--highlight-color) 50%,\n var(--base-color) 100%\n )\n );\n transform: translateX(-100%);\n\n animation-name: react-loading-skeleton;\n animation-direction: var(--animation-direction);\n animation-duration: var(--animation-duration);\n animation-timing-function: ease-in-out;\n animation-iteration-count: infinite;\n}\n\n@media (prefers-reduced-motion) {\n .react-loading-skeleton {\n --pseudo-element-display: none; /* Disable animation */\n }\n}\n";
|
|
25151
|
-
styleInject(css_248z);
|
|
25150
|
+
var css_248z$1 = "@keyframes react-loading-skeleton {\n 100% {\n transform: translateX(100%);\n }\n}\n\n.react-loading-skeleton {\n --base-color: #ebebeb;\n --highlight-color: #f5f5f5;\n --animation-duration: 1.5s;\n --animation-direction: normal;\n --pseudo-element-display: block; /* Enable animation */\n\n background-color: var(--base-color);\n\n width: 100%;\n border-radius: 0.25rem;\n display: inline-flex;\n line-height: 1;\n\n position: relative;\n user-select: none;\n overflow: hidden;\n}\n\n.react-loading-skeleton::after {\n content: ' ';\n display: var(--pseudo-element-display);\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background-repeat: no-repeat;\n background-image: var(\n --custom-highlight-background,\n linear-gradient(\n 90deg,\n var(--base-color) 0%,\n var(--highlight-color) 50%,\n var(--base-color) 100%\n )\n );\n transform: translateX(-100%);\n\n animation-name: react-loading-skeleton;\n animation-direction: var(--animation-direction);\n animation-duration: var(--animation-duration);\n animation-timing-function: ease-in-out;\n animation-iteration-count: infinite;\n}\n\n@media (prefers-reduced-motion) {\n .react-loading-skeleton {\n --pseudo-element-display: none; /* Disable animation */\n }\n}\n";
|
|
25151
|
+
styleInject(css_248z$1);
|
|
25152
25152
|
|
|
25153
25153
|
const OneColumnContainer = props => {
|
|
25154
25154
|
const {
|
|
@@ -25345,7 +25345,7 @@ const ControlsContainer$7 = styled.div`
|
|
|
25345
25345
|
box-sizing: border-box;
|
|
25346
25346
|
}
|
|
25347
25347
|
`;
|
|
25348
|
-
const Controls$
|
|
25348
|
+
const Controls$7 = styled.div`
|
|
25349
25349
|
display: flex;
|
|
25350
25350
|
flex-direction: column;
|
|
25351
25351
|
width: 100%;
|
|
@@ -25413,7 +25413,7 @@ const FormattedValue$3 = props => {
|
|
|
25413
25413
|
height: height,
|
|
25414
25414
|
width: width,
|
|
25415
25415
|
textcolor: textcolor
|
|
25416
|
-
}, /*#__PURE__*/React$1.createElement(Controls$
|
|
25416
|
+
}, /*#__PURE__*/React$1.createElement(Controls$7, {
|
|
25417
25417
|
className: "Controls",
|
|
25418
25418
|
height: height,
|
|
25419
25419
|
width: width
|
|
@@ -25473,7 +25473,7 @@ const ControlsContainer$6 = styled.div`
|
|
|
25473
25473
|
height: ${props => props.height};
|
|
25474
25474
|
min-width: 250px;
|
|
25475
25475
|
`;
|
|
25476
|
-
const Controls$
|
|
25476
|
+
const Controls$6 = styled.div`
|
|
25477
25477
|
height: 100%;
|
|
25478
25478
|
width: 100%;
|
|
25479
25479
|
background: white;
|
|
@@ -25606,7 +25606,7 @@ const ControlsContainer$5 = styled.div`
|
|
|
25606
25606
|
box-sizing: border-box;
|
|
25607
25607
|
}
|
|
25608
25608
|
`;
|
|
25609
|
-
const Controls$
|
|
25609
|
+
const Controls$5 = styled.div`
|
|
25610
25610
|
display: flex;
|
|
25611
25611
|
gap: 20px;
|
|
25612
25612
|
flex-direction: column;
|
|
@@ -25669,7 +25669,7 @@ const PerformanceAnalyticsLegend = props => {
|
|
|
25669
25669
|
className: className,
|
|
25670
25670
|
height: height,
|
|
25671
25671
|
width: width
|
|
25672
|
-
}, legendData?.length > 0 ? /*#__PURE__*/React$1.createElement(Controls$
|
|
25672
|
+
}, legendData?.length > 0 ? /*#__PURE__*/React$1.createElement(Controls$5, {
|
|
25673
25673
|
height: height,
|
|
25674
25674
|
width: width
|
|
25675
25675
|
}, /*#__PURE__*/React$1.createElement(LegendDataContainer, {
|
|
@@ -25837,7 +25837,7 @@ const BarChartsByWeeks = props => {
|
|
|
25837
25837
|
height: height,
|
|
25838
25838
|
width: width,
|
|
25839
25839
|
ref: controlsContainerRef
|
|
25840
|
-
}, /*#__PURE__*/React$1.createElement(Controls$
|
|
25840
|
+
}, /*#__PURE__*/React$1.createElement(Controls$6, {
|
|
25841
25841
|
height: getControlsHeight()
|
|
25842
25842
|
}, showTitle && /*#__PURE__*/React$1.createElement(TitleAndValueContainer$2, null, /*#__PURE__*/React$1.createElement(Title$b, null, title), /*#__PURE__*/React$1.createElement(FormattedValue$3, {
|
|
25843
25843
|
title: headerValueTopTitle,
|
|
@@ -26043,7 +26043,7 @@ const ControlsContainer$4 = styled.div`
|
|
|
26043
26043
|
box-sizing: border-box;
|
|
26044
26044
|
}
|
|
26045
26045
|
`;
|
|
26046
|
-
const Controls$
|
|
26046
|
+
const Controls$4 = styled.div`
|
|
26047
26047
|
display: flex;
|
|
26048
26048
|
flex-direction: column;
|
|
26049
26049
|
width: 100%;
|
|
@@ -26269,7 +26269,7 @@ const TotalDoughnutChart = props => {
|
|
|
26269
26269
|
}, legendData.length === 0 || legendData.every(item => item.value === undefined || item.value === null) ? /*#__PURE__*/React$1.createElement(NoDataFoundMessage, {
|
|
26270
26270
|
className: "NoDataFoundMessage",
|
|
26271
26271
|
noDataText: noDataText
|
|
26272
|
-
}) : /*#__PURE__*/React$1.createElement(Controls$
|
|
26272
|
+
}) : /*#__PURE__*/React$1.createElement(Controls$4, {
|
|
26273
26273
|
className: "Controls",
|
|
26274
26274
|
height: height,
|
|
26275
26275
|
width: width
|
|
@@ -28521,7 +28521,7 @@ const ControlsContainer$1 = styled.div`
|
|
|
28521
28521
|
height: ${props => props.height};
|
|
28522
28522
|
min-width: 250px;
|
|
28523
28523
|
`;
|
|
28524
|
-
const Controls$
|
|
28524
|
+
const Controls$3 = styled.div`
|
|
28525
28525
|
height: 100%;
|
|
28526
28526
|
width: 100%;
|
|
28527
28527
|
background: white;
|
|
@@ -28706,7 +28706,7 @@ const BarChart = props => {
|
|
|
28706
28706
|
height: height,
|
|
28707
28707
|
width: width,
|
|
28708
28708
|
ref: controlsContainerRef
|
|
28709
|
-
}, /*#__PURE__*/React$1.createElement(Controls$
|
|
28709
|
+
}, /*#__PURE__*/React$1.createElement(Controls$3, null, /*#__PURE__*/React$1.createElement(Title$3, null, title), /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
28710
28710
|
width: "100%",
|
|
28711
28711
|
height: 400
|
|
28712
28712
|
}, /*#__PURE__*/React$1.createElement(BarChart$1, {
|
|
@@ -28870,7 +28870,7 @@ const LegendContainer = styled.div`
|
|
|
28870
28870
|
width: ${props => `${props.width}px`};
|
|
28871
28871
|
bottom: 20px;
|
|
28872
28872
|
`;
|
|
28873
|
-
const Controls$
|
|
28873
|
+
const Controls$2 = styled.div`
|
|
28874
28874
|
/* height: calc(100% - 30px); */
|
|
28875
28875
|
height: 100%;
|
|
28876
28876
|
display: flex;
|
|
@@ -29134,7 +29134,7 @@ const DoubleBarSingleLine = props => {
|
|
|
29134
29134
|
hasScroll: hasScroll
|
|
29135
29135
|
}, data.length === 0 ? /*#__PURE__*/React$1.createElement(NoDataFoundMessage, {
|
|
29136
29136
|
noDataText: noDataText
|
|
29137
|
-
}) : /*#__PURE__*/React$1.createElement(Controls$
|
|
29137
|
+
}) : /*#__PURE__*/React$1.createElement(Controls$2, {
|
|
29138
29138
|
className: "Controls"
|
|
29139
29139
|
}, title && title.trim() !== '' && /*#__PURE__*/React$1.createElement(Title$2, null, title), /*#__PURE__*/React$1.createElement(ChartsWrapper, {
|
|
29140
29140
|
width: hasScroll ? `${data.length * 178}px` : 'auto'
|
|
@@ -29224,7 +29224,7 @@ const AreaChartContaner = styled.div`
|
|
|
29224
29224
|
height: ${props => props.height};
|
|
29225
29225
|
min-width: 1100px;
|
|
29226
29226
|
`;
|
|
29227
|
-
const HeaderContainer$
|
|
29227
|
+
const HeaderContainer$2 = styled.div`
|
|
29228
29228
|
display: flex;
|
|
29229
29229
|
justify-content: space-between;
|
|
29230
29230
|
padding: 10px 40px;
|
|
@@ -29283,7 +29283,7 @@ const ControlsContainer = styled.div`
|
|
|
29283
29283
|
font-family: Poppins;
|
|
29284
29284
|
margin: 0;
|
|
29285
29285
|
`;
|
|
29286
|
-
const Controls = styled.div`
|
|
29286
|
+
const Controls$1 = styled.div`
|
|
29287
29287
|
display: flex;
|
|
29288
29288
|
align-items: center;
|
|
29289
29289
|
`;
|
|
@@ -29329,7 +29329,7 @@ const CheckBox = props => {
|
|
|
29329
29329
|
fontSize: fontSize,
|
|
29330
29330
|
width: width,
|
|
29331
29331
|
height: height
|
|
29332
|
-
}, /*#__PURE__*/React$1.createElement(Controls, {
|
|
29332
|
+
}, /*#__PURE__*/React$1.createElement(Controls$1, {
|
|
29333
29333
|
className: "Controls",
|
|
29334
29334
|
"data-testid": "controls"
|
|
29335
29335
|
}, checkedState ? /*#__PURE__*/React$1.createElement(CheckBoxIconContainer, {
|
|
@@ -29561,7 +29561,7 @@ const AreaChart = props => {
|
|
|
29561
29561
|
noDataText: "",
|
|
29562
29562
|
width: width,
|
|
29563
29563
|
height: height
|
|
29564
|
-
}) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer$
|
|
29564
|
+
}) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer$2, {
|
|
29565
29565
|
"data-testid": "header-container"
|
|
29566
29566
|
}, /*#__PURE__*/React$1.createElement(Title$1, {
|
|
29567
29567
|
"data-testid": "title"
|
|
@@ -30055,7 +30055,7 @@ const BreakdownPanelContainer = styled.div`
|
|
|
30055
30055
|
height: ${props => props.height};
|
|
30056
30056
|
min-width: 1100px;
|
|
30057
30057
|
`;
|
|
30058
|
-
const HeaderContainer = styled.div`
|
|
30058
|
+
const HeaderContainer$1 = styled.div`
|
|
30059
30059
|
display: flex;
|
|
30060
30060
|
justify-content: space-between;
|
|
30061
30061
|
align-items: center;
|
|
@@ -30128,7 +30128,7 @@ const BreakdownPanel = props => {
|
|
|
30128
30128
|
noDataText: "",
|
|
30129
30129
|
width: width,
|
|
30130
30130
|
height: height
|
|
30131
|
-
}) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer, {
|
|
30131
|
+
}) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer$1, {
|
|
30132
30132
|
"data-testid": "header-container"
|
|
30133
30133
|
}, /*#__PURE__*/React$1.createElement(Title, {
|
|
30134
30134
|
"data-testid": "title"
|
|
@@ -30154,264 +30154,2070 @@ const BreakdownPanel = props => {
|
|
|
30154
30154
|
}))))));
|
|
30155
30155
|
};
|
|
30156
30156
|
|
|
30157
|
-
const
|
|
30158
|
-
|
|
30159
|
-
|
|
30160
|
-
|
|
30161
|
-
|
|
30162
|
-
|
|
30163
|
-
|
|
30164
|
-
|
|
30165
|
-
|
|
30166
|
-
|
|
30167
|
-
|
|
30168
|
-
|
|
30169
|
-
|
|
30170
|
-
|
|
30171
|
-
|
|
30172
|
-
justify-content: space-between;
|
|
30157
|
+
const BubbleChartContainer = styled.div`
|
|
30158
|
+
position: relative;
|
|
30159
|
+
width: ${props => props.width};
|
|
30160
|
+
height: ${props => props.height};
|
|
30161
|
+
display: flex;
|
|
30162
|
+
flex-direction: column;
|
|
30163
|
+
background-color: ${props => props.backgroundColor};
|
|
30164
|
+
border-radius: 8px;
|
|
30165
|
+
padding: 10px;
|
|
30166
|
+
box-sizing: border-box;
|
|
30167
|
+
font-family: "Poppins", sans-serif;
|
|
30168
|
+
min-width: 800px;
|
|
30169
|
+
|
|
30170
|
+
/* Enable proper overflow handling */
|
|
30171
|
+
overflow: hidden;
|
|
30173
30172
|
`;
|
|
30174
|
-
|
|
30175
|
-
|
|
30176
|
-
|
|
30177
|
-
|
|
30173
|
+
styled.div`
|
|
30174
|
+
position: absolute;
|
|
30175
|
+
font-family: "Poppins", sans-serif;
|
|
30176
|
+
font-size: 12px;
|
|
30177
|
+
font-weight: 500;
|
|
30178
|
+
color: #555;
|
|
30179
|
+
text-align: center;
|
|
30180
|
+
|
|
30181
|
+
&.top-left {
|
|
30182
|
+
top: 20px;
|
|
30183
|
+
left: 20px;
|
|
30184
|
+
}
|
|
30185
|
+
|
|
30186
|
+
&.top-right {
|
|
30187
|
+
top: 20px;
|
|
30188
|
+
right: 20px;
|
|
30189
|
+
}
|
|
30190
|
+
|
|
30191
|
+
&.bottom-left {
|
|
30192
|
+
bottom: 20px;
|
|
30193
|
+
left: 20px;
|
|
30194
|
+
}
|
|
30195
|
+
|
|
30196
|
+
&.bottom-right {
|
|
30197
|
+
bottom: 20px;
|
|
30198
|
+
right: 20px;
|
|
30199
|
+
}
|
|
30178
30200
|
`;
|
|
30179
|
-
const
|
|
30180
|
-
|
|
30181
|
-
|
|
30182
|
-
|
|
30183
|
-
|
|
30184
|
-
|
|
30201
|
+
const CustomTooltipContainer = styled.div`
|
|
30202
|
+
background-color: white;
|
|
30203
|
+
border-radius: 6px;
|
|
30204
|
+
z-index: 1000;
|
|
30205
|
+
padding: 10px 14px;
|
|
30206
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
|
|
30207
|
+
max-width: 220px;
|
|
30208
|
+
font-family: "Poppins", sans-serif;
|
|
30209
|
+
|
|
30210
|
+
h4 {
|
|
30185
30211
|
margin: 0 0 8px;
|
|
30186
|
-
|
|
30187
|
-
|
|
30188
|
-
|
|
30189
|
-
|
|
30190
|
-
|
|
30191
|
-
|
|
30192
|
-
|
|
30193
|
-
|
|
30194
|
-
|
|
30195
|
-
|
|
30196
|
-
|
|
30197
|
-
|
|
30198
|
-
|
|
30199
|
-
|
|
30200
|
-
|
|
30201
|
-
|
|
30202
|
-
|
|
30203
|
-
font-size: 18px;
|
|
30204
|
-
color: #8B8989;
|
|
30205
|
-
line-height: 1;
|
|
30206
|
-
&.overload {
|
|
30207
|
-
position: absolute;
|
|
30208
|
-
top: ${props => props.goalValuePosition}px;
|
|
30209
|
-
left: 0;
|
|
30210
|
-
right: 0;
|
|
30211
|
-
z-index: 2;
|
|
30212
|
-
margin: 0 auto;
|
|
30213
|
-
width: 40%;
|
|
30214
|
-
display: inline;
|
|
30215
|
-
padding: 0px 8px;
|
|
30216
|
-
border: 2px solid #F2F2F2;
|
|
30217
|
-
border-bottom: none;
|
|
30218
|
-
border-radius: 6px 6px 0px 0px;
|
|
30219
|
-
background-color: white;
|
|
30212
|
+
font-size: 14px;
|
|
30213
|
+
font-weight: 600;
|
|
30214
|
+
}
|
|
30215
|
+
|
|
30216
|
+
p {
|
|
30217
|
+
margin: 3px 0;
|
|
30218
|
+
font-size: 12px;
|
|
30219
|
+
color: #555;
|
|
30220
|
+
}
|
|
30221
|
+
|
|
30222
|
+
@media (max-width: 768px) {
|
|
30223
|
+
padding: 8px 12px;
|
|
30224
|
+
max-width: 180px;
|
|
30225
|
+
|
|
30226
|
+
h4 {
|
|
30227
|
+
font-size: 12px;
|
|
30228
|
+
margin: 0 0 6px;
|
|
30220
30229
|
}
|
|
30230
|
+
|
|
30231
|
+
p {
|
|
30232
|
+
font-size: 10px;
|
|
30233
|
+
}
|
|
30234
|
+
}
|
|
30221
30235
|
`;
|
|
30222
|
-
const
|
|
30223
|
-
|
|
30224
|
-
|
|
30225
|
-
|
|
30226
|
-
|
|
30227
|
-
|
|
30228
|
-
|
|
30229
|
-
|
|
30230
|
-
|
|
30231
|
-
|
|
30232
|
-
|
|
30233
|
-
|
|
30234
|
-
|
|
30235
|
-
|
|
30236
|
-
width: 100%;
|
|
30237
|
-
height: 0;
|
|
30238
|
-
border-top: 4px dashed ${props => props.color};
|
|
30236
|
+
const TooltipMetric = styled.div`
|
|
30237
|
+
display: flex;
|
|
30238
|
+
justify-content: space-between;
|
|
30239
|
+
margin: 5px 0;
|
|
30240
|
+
font-size: 12px;
|
|
30241
|
+
|
|
30242
|
+
span:last-child {
|
|
30243
|
+
font-weight: 500;
|
|
30244
|
+
}
|
|
30245
|
+
|
|
30246
|
+
@media (max-width: 768px) {
|
|
30247
|
+
font-size: 10px;
|
|
30248
|
+
margin: 4px 0;
|
|
30249
|
+
}
|
|
30239
30250
|
`;
|
|
30240
|
-
|
|
30241
|
-
|
|
30242
|
-
|
|
30243
|
-
|
|
30251
|
+
styled.div`
|
|
30252
|
+
position: relative;
|
|
30253
|
+
width: 100%;
|
|
30254
|
+
height: 100%;
|
|
30244
30255
|
`;
|
|
30245
|
-
const
|
|
30246
|
-
|
|
30256
|
+
const HeaderContainer = styled.div`
|
|
30257
|
+
display: flex;
|
|
30258
|
+
justify-content: space-between;
|
|
30259
|
+
align-items: baseline;
|
|
30260
|
+
padding: 0;
|
|
30261
|
+
margin-bottom: 10px;
|
|
30247
30262
|
`;
|
|
30248
|
-
const
|
|
30249
|
-
|
|
30250
|
-
|
|
30251
|
-
|
|
30252
|
-
|
|
30263
|
+
const ChartTitle = styled.h2`
|
|
30264
|
+
font-family: "Poppins", sans-serif;
|
|
30265
|
+
font-size: 18px;
|
|
30266
|
+
font-weight: 400;
|
|
30267
|
+
margin: 0;
|
|
30268
|
+
color: #212121;
|
|
30253
30269
|
`;
|
|
30254
|
-
const
|
|
30255
|
-
|
|
30256
|
-
|
|
30270
|
+
const ChartSubtitle = styled.p`
|
|
30271
|
+
font-family: "Poppins", sans-serif;
|
|
30272
|
+
font-size: 14px;
|
|
30273
|
+
font-weight: 500;
|
|
30274
|
+
color: #484A4C;
|
|
30275
|
+
margin: 0;
|
|
30257
30276
|
`;
|
|
30258
|
-
const
|
|
30259
|
-
|
|
30260
|
-
|
|
30261
|
-
|
|
30262
|
-
|
|
30277
|
+
const ChartContainer = styled.div`
|
|
30278
|
+
position: relative;
|
|
30279
|
+
width: 100%;
|
|
30280
|
+
height: 90%; /* Reduced from 93% to make room for the zoom controls */
|
|
30281
|
+
flex: 1;
|
|
30263
30282
|
`;
|
|
30264
|
-
|
|
30265
|
-
|
|
30266
|
-
|
|
30267
|
-
|
|
30268
|
-
|
|
30283
|
+
|
|
30284
|
+
/* Updated Zoom Controls Styles to match the new design */
|
|
30285
|
+
const ZoomControlsContainer = styled.div`
|
|
30286
|
+
display: flex;
|
|
30287
|
+
align-items: center;
|
|
30288
|
+
align-self: flex-start;
|
|
30289
|
+
margin-top: 10px;
|
|
30290
|
+
background: linear-gradient(to right, rgba(255, 255, 255, 0.98), rgba(245, 245, 245, 0.92));
|
|
30291
|
+
border-radius: 8px;
|
|
30292
|
+
padding: 6px 6px 6px 12px;
|
|
30293
|
+
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
|
|
30294
|
+
z-index: 10;
|
|
30295
|
+
font-family: "Poppins", sans-serif;
|
|
30296
|
+
backdrop-filter: blur(8px);
|
|
30297
|
+
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
|
30269
30298
|
`;
|
|
30270
|
-
const
|
|
30271
|
-
|
|
30299
|
+
const ZoomPercentage = styled.span`
|
|
30300
|
+
font-size: 18px;
|
|
30301
|
+
font-weight: 500;
|
|
30302
|
+
color: #726F6F;
|
|
30303
|
+
margin: 0;
|
|
30304
|
+
min-width: 50px;
|
|
30272
30305
|
`;
|
|
30273
|
-
const
|
|
30274
|
-
|
|
30275
|
-
|
|
30276
|
-
|
|
30277
|
-
|
|
30278
|
-
|
|
30306
|
+
const ZoomButton = styled.button`
|
|
30307
|
+
width: 26px;
|
|
30308
|
+
height: 20px;
|
|
30309
|
+
border: none;
|
|
30310
|
+
background: none;
|
|
30311
|
+
font-size: 24px;
|
|
30312
|
+
font-weight: 500;
|
|
30313
|
+
color: #726F6F;
|
|
30314
|
+
cursor: pointer;
|
|
30315
|
+
display: flex;
|
|
30316
|
+
align-items: center;
|
|
30317
|
+
justify-content: center;
|
|
30318
|
+
padding: 0;
|
|
30319
|
+
margin: 0 ;
|
|
30320
|
+
|
|
30321
|
+
&:hover {
|
|
30322
|
+
color: #333;
|
|
30323
|
+
}
|
|
30324
|
+
|
|
30325
|
+
&:focus {
|
|
30326
|
+
outline: none;
|
|
30327
|
+
}
|
|
30279
30328
|
`;
|
|
30329
|
+
const ZoomResetButton = styled.button`
|
|
30330
|
+
font-family: "Poppins", sans-serif;
|
|
30331
|
+
font-size: 14px;
|
|
30332
|
+
font-weight: 400;
|
|
30333
|
+
height: 32px;
|
|
30334
|
+
padding: 0 12px;
|
|
30335
|
+
margin-left: 5px;
|
|
30336
|
+
border-radius: 8px;
|
|
30337
|
+
background-color: white;
|
|
30338
|
+
border: 1px solid #ddd;
|
|
30339
|
+
cursor: pointer;
|
|
30340
|
+
color: #212121;
|
|
30341
|
+
background: linear-gradient(to right, rgba(255, 255, 255, 0.98), rgba(245, 245, 245, 0.92));
|
|
30342
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
30343
|
+
transition: all 0.2s ease-in-out;
|
|
30280
30344
|
|
|
30281
|
-
|
|
30345
|
+
&:hover {
|
|
30346
|
+
background: linear-gradient(to right, #f0f0f0, #eaeaea);
|
|
30347
|
+
border-color: #ccc;
|
|
30348
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
|
30349
|
+
}
|
|
30350
|
+
|
|
30351
|
+
&:active {
|
|
30352
|
+
background: #e0e0e0;
|
|
30353
|
+
transform: scale(0.98);
|
|
30354
|
+
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
|
|
30355
|
+
}
|
|
30356
|
+
|
|
30357
|
+
&:focus {
|
|
30358
|
+
outline: none;
|
|
30359
|
+
box-shadow: 0 0 0 3px rgba(100, 150, 250, 0.4);
|
|
30360
|
+
}
|
|
30361
|
+
`;
|
|
30362
|
+
|
|
30363
|
+
// Enhanced color palette with bubble-like transparency and gradients
|
|
30364
|
+
const defaultColorPalette = [
|
|
30365
|
+
// Top Left - Yellow Bubbles
|
|
30366
|
+
'rgba(255, 249, 220, 0.7)',
|
|
30367
|
+
// Inner highlight
|
|
30368
|
+
'rgba(255, 235, 165, 0.4)',
|
|
30369
|
+
// Outer edge
|
|
30370
|
+
|
|
30371
|
+
// Top Right - Green Bubbles
|
|
30372
|
+
'rgba(235, 255, 240, 0.7)',
|
|
30373
|
+
// Inner highlight
|
|
30374
|
+
'rgba(190, 235, 200, 0.4)',
|
|
30375
|
+
// Outer edge
|
|
30376
|
+
|
|
30377
|
+
// Bottom Left - Pink Bubbles
|
|
30378
|
+
'rgba(255, 235, 240, 0.7)',
|
|
30379
|
+
// Inner highlight
|
|
30380
|
+
'rgba(255, 190, 200, 0.4)',
|
|
30381
|
+
// Outer edge
|
|
30382
|
+
|
|
30383
|
+
// Bottom Right - Cream/Yellow Bubbles
|
|
30384
|
+
'rgba(255, 250, 230, 0.7)',
|
|
30385
|
+
// Inner highlight
|
|
30386
|
+
'rgba(255, 235, 180, 0.4)' // Outer edge
|
|
30387
|
+
];
|
|
30388
|
+
|
|
30389
|
+
// Main component
|
|
30390
|
+
const BubbleChart = _ref => {
|
|
30391
|
+
let {
|
|
30392
|
+
data = [],
|
|
30393
|
+
title = 'Event Performance Based on Incrementality',
|
|
30394
|
+
subtitle = '* Total cost is reflected by the circle size',
|
|
30395
|
+
leftHeader = 'Low INC Sales ROI',
|
|
30396
|
+
rightHeader = 'High INC Sales ROI',
|
|
30397
|
+
topHeader = 'High INC Sales',
|
|
30398
|
+
bottomHeader = 'Low INC Sales',
|
|
30399
|
+
colorPalette = defaultColorPalette,
|
|
30400
|
+
height = '600px',
|
|
30401
|
+
width = '100%',
|
|
30402
|
+
backgroundColor = 'white',
|
|
30403
|
+
showAxis = false
|
|
30404
|
+
} = _ref;
|
|
30405
|
+
// Calculate the medians and domain for raw X, Y, and Z values
|
|
30282
30406
|
const {
|
|
30283
|
-
|
|
30284
|
-
|
|
30285
|
-
|
|
30286
|
-
|
|
30287
|
-
|
|
30288
|
-
|
|
30289
|
-
|
|
30290
|
-
|
|
30291
|
-
|
|
30292
|
-
|
|
30293
|
-
|
|
30294
|
-
|
|
30295
|
-
|
|
30296
|
-
|
|
30297
|
-
|
|
30298
|
-
} = props;
|
|
30299
|
-
const [top, setTop] = useState(0);
|
|
30300
|
-
const [goalValuePosition, setGoalValuePosition] = useState(0);
|
|
30301
|
-
const [containerHeight, setContainerHeight] = useState(0); // State to store container height
|
|
30302
|
-
const containerRef = useRef(null); // Ref for BatteryChartContainer
|
|
30407
|
+
xMedian,
|
|
30408
|
+
yMedian,
|
|
30409
|
+
xDomain,
|
|
30410
|
+
yDomain,
|
|
30411
|
+
zRange
|
|
30412
|
+
} = useMemo(() => {
|
|
30413
|
+
if (!data || !Array.isArray(data) || data.length === 0) {
|
|
30414
|
+
return {
|
|
30415
|
+
xMedian: 0,
|
|
30416
|
+
yMedian: 0,
|
|
30417
|
+
xDomain: [0, 100],
|
|
30418
|
+
yDomain: [0, 100],
|
|
30419
|
+
zRange: [0, 3600]
|
|
30420
|
+
};
|
|
30421
|
+
}
|
|
30303
30422
|
|
|
30304
|
-
|
|
30305
|
-
|
|
30306
|
-
|
|
30423
|
+
// Extract x, y, and size values
|
|
30424
|
+
const xValues = data.map(item => item.x).filter(x => x !== undefined && x !== null);
|
|
30425
|
+
const yValues = data.map(item => item.y).filter(y => y !== undefined && y !== null);
|
|
30426
|
+
const sizeValues = data.map(item => item.size).filter(size => size !== undefined && size !== null);
|
|
30427
|
+
|
|
30428
|
+
// Calculate min and max values
|
|
30429
|
+
const minX = Math.min(...xValues);
|
|
30430
|
+
const maxX = Math.max(...xValues);
|
|
30431
|
+
const minY = Math.min(...yValues);
|
|
30432
|
+
const maxY = Math.max(...yValues);
|
|
30433
|
+
Math.min(...sizeValues);
|
|
30434
|
+
const maxSize = Math.max(...sizeValues);
|
|
30435
|
+
|
|
30436
|
+
// Calculate medians
|
|
30437
|
+
const calculateMedian = arr => {
|
|
30438
|
+
if (!arr || arr.length === 0) return 0;
|
|
30439
|
+
const sorted = [...arr].sort((a, b) => a - b);
|
|
30440
|
+
const middle = Math.floor(sorted.length / 2);
|
|
30441
|
+
if (sorted.length % 2 === 1) {
|
|
30442
|
+
return sorted[middle];
|
|
30443
|
+
}
|
|
30444
|
+
return (sorted[middle - 1] + sorted[middle]) / 2;
|
|
30445
|
+
};
|
|
30446
|
+
const medianX = calculateMedian(xValues);
|
|
30447
|
+
const medianY = calculateMedian(yValues);
|
|
30307
30448
|
|
|
30308
|
-
|
|
30309
|
-
|
|
30310
|
-
|
|
30311
|
-
|
|
30312
|
-
|
|
30313
|
-
|
|
30314
|
-
|
|
30315
|
-
// Fill from bottom up
|
|
30316
|
-
color: index >= totalSegmentsLines - completedSegments ? color : "#e5e7eb" // Completed or remaining color
|
|
30317
|
-
}));
|
|
30449
|
+
// Calculate domains based on median-centered logic
|
|
30450
|
+
const calculateDomainBasedOnMedian = (min, max, median) => {
|
|
30451
|
+
const distance = Math.max(Math.abs(max - median), Math.abs(min - median));
|
|
30452
|
+
return [median - distance, median + distance];
|
|
30453
|
+
};
|
|
30454
|
+
const xDom = calculateDomainBasedOnMedian(minX, maxX, medianX);
|
|
30455
|
+
const yDom = calculateDomainBasedOnMedian(minY, maxY, medianY);
|
|
30318
30456
|
|
|
30319
|
-
|
|
30320
|
-
|
|
30321
|
-
|
|
30322
|
-
|
|
30323
|
-
|
|
30324
|
-
|
|
30325
|
-
|
|
30326
|
-
|
|
30327
|
-
|
|
30328
|
-
|
|
30329
|
-
}));
|
|
30457
|
+
// Determine z-axis range scaled appropriately
|
|
30458
|
+
const zRng = [0, maxSize * 7];
|
|
30459
|
+
return {
|
|
30460
|
+
xMedian: medianX,
|
|
30461
|
+
yMedian: medianY,
|
|
30462
|
+
xDomain: xDom,
|
|
30463
|
+
yDomain: yDom,
|
|
30464
|
+
zRange: zRng
|
|
30465
|
+
};
|
|
30466
|
+
}, [data]);
|
|
30330
30467
|
|
|
30331
|
-
|
|
30332
|
-
|
|
30333
|
-
|
|
30468
|
+
// Init viewDomain with calculated domain values
|
|
30469
|
+
const fullDomain = useMemo(() => ({
|
|
30470
|
+
x: xDomain,
|
|
30471
|
+
y: yDomain
|
|
30472
|
+
}), [xDomain, yDomain]);
|
|
30334
30473
|
|
|
30335
|
-
//
|
|
30474
|
+
// State for current view domain
|
|
30475
|
+
const [viewDomain, setViewDomain] = useState(fullDomain);
|
|
30476
|
+
const [zoomLevel, setZoomLevel] = useState(100);
|
|
30477
|
+
|
|
30478
|
+
// Drag state
|
|
30479
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
30480
|
+
const [dragStart, setDragStart] = useState({
|
|
30481
|
+
x: 0,
|
|
30482
|
+
y: 0
|
|
30483
|
+
});
|
|
30484
|
+
const [domainStart, setDomainStart] = useState(fullDomain);
|
|
30485
|
+
|
|
30486
|
+
// Refs for the chart container
|
|
30487
|
+
const containerRef = useRef(null);
|
|
30488
|
+
const scatterChartRef = useRef(null);
|
|
30489
|
+
|
|
30490
|
+
// Set up initial domain
|
|
30336
30491
|
useEffect(() => {
|
|
30337
|
-
|
|
30338
|
-
|
|
30339
|
-
|
|
30340
|
-
|
|
30341
|
-
|
|
30342
|
-
|
|
30343
|
-
|
|
30492
|
+
// Set initial viewDomain from fullDomain
|
|
30493
|
+
setViewDomain(fullDomain);
|
|
30494
|
+
}, [fullDomain]);
|
|
30495
|
+
|
|
30496
|
+
// Function to get gradient fill based on quadrant
|
|
30497
|
+
const getFill = useCallback((x, y) => {
|
|
30498
|
+
if (x < xMedian && y > yMedian) return 'url(#topLeftGradient)'; // Top Left
|
|
30499
|
+
if (x >= xMedian && y > yMedian) return 'url(#topRightGradient)'; // Top Right
|
|
30500
|
+
if (x < xMedian && y <= yMedian) return 'url(#bottomLeftGradient)'; // Bottom Left
|
|
30501
|
+
if (x >= xMedian && y <= yMedian) return 'url(#bottomRightGradient)'; // Bottom Right
|
|
30502
|
+
return 'gray'; // fallback
|
|
30503
|
+
}, [xMedian, yMedian]);
|
|
30504
|
+
|
|
30505
|
+
// CustomTooltip component inside BubbleChart
|
|
30506
|
+
const CustomTooltip = useCallback(_ref2 => {
|
|
30507
|
+
let {
|
|
30508
|
+
active,
|
|
30509
|
+
payload
|
|
30510
|
+
} = _ref2;
|
|
30511
|
+
if (active && payload && payload.length && payload[0].payload.tooltip) {
|
|
30512
|
+
const data = payload[0].payload;
|
|
30513
|
+
return /*#__PURE__*/React$1.createElement(CustomTooltipContainer, {
|
|
30514
|
+
"data-testid": "tooltip-container"
|
|
30515
|
+
}, /*#__PURE__*/React$1.createElement("h4", {
|
|
30516
|
+
"data-testid": "tooltip-title"
|
|
30517
|
+
}, data.tooltip.title), data.tooltip.description && /*#__PURE__*/React$1.createElement(TooltipMetric, {
|
|
30518
|
+
"data-testid": "tooltip-description"
|
|
30519
|
+
}, /*#__PURE__*/React$1.createElement("span", null, data.tooltip.description)), /*#__PURE__*/React$1.createElement(TooltipMetric, {
|
|
30520
|
+
"data-testid": "tooltip-cost"
|
|
30521
|
+
}, /*#__PURE__*/React$1.createElement("span", null, "Total cost:"), /*#__PURE__*/React$1.createElement("span", null, formatCurrency(data.tooltip.cost))), /*#__PURE__*/React$1.createElement(TooltipMetric, {
|
|
30522
|
+
"data-testid": "tooltip-sales"
|
|
30523
|
+
}, /*#__PURE__*/React$1.createElement("span", null, "INC Sales:"), /*#__PURE__*/React$1.createElement("span", null, formatCurrency(data.tooltip.incSales))), /*#__PURE__*/React$1.createElement(TooltipMetric, {
|
|
30524
|
+
"data-testid": "tooltip-roi"
|
|
30525
|
+
}, /*#__PURE__*/React$1.createElement("span", null, "INC Sales ROI:"), /*#__PURE__*/React$1.createElement("span", null, formatROI(data.tooltip.roi))), /*#__PURE__*/React$1.createElement(TooltipMetric, {
|
|
30526
|
+
"data-testid": "tooltip-units"
|
|
30527
|
+
}, /*#__PURE__*/React$1.createElement("span", null, "INC Units:"), /*#__PURE__*/React$1.createElement("span", null, formatUnits(data.tooltip.units))));
|
|
30528
|
+
}
|
|
30529
|
+
return null;
|
|
30530
|
+
}, []);
|
|
30344
30531
|
|
|
30345
|
-
|
|
30346
|
-
|
|
30532
|
+
// Process all chart data - use original data values
|
|
30533
|
+
const allChartData = useMemo(() => {
|
|
30534
|
+
return data.map((item, index) => {
|
|
30535
|
+
if (item.x === undefined || item.y === undefined || item.size === undefined) {
|
|
30536
|
+
console.warn('Skipping data item with missing values:', item);
|
|
30537
|
+
return null;
|
|
30538
|
+
}
|
|
30539
|
+
const tooltipInfo = {
|
|
30540
|
+
title: item.name || 'Marketing event',
|
|
30541
|
+
description: item.description || '',
|
|
30542
|
+
cost: item.size || 0,
|
|
30543
|
+
units: item.units || 0,
|
|
30544
|
+
roi: item.x || 0,
|
|
30545
|
+
incSales: item.y || 0,
|
|
30546
|
+
...(item.tooltip || {})
|
|
30547
|
+
};
|
|
30548
|
+
return {
|
|
30549
|
+
x: item.x,
|
|
30550
|
+
// Use original x value
|
|
30551
|
+
y: item.y,
|
|
30552
|
+
// Use original y value
|
|
30553
|
+
z: item.size,
|
|
30554
|
+
// Use original size value
|
|
30555
|
+
tooltip: tooltipInfo,
|
|
30556
|
+
fill: getFill(item.x, item.y),
|
|
30557
|
+
key: `bubble-${index}` // Use index for stable keys
|
|
30558
|
+
};
|
|
30559
|
+
}).filter(Boolean); // Filter out null items
|
|
30560
|
+
}, [data, getFill]);
|
|
30561
|
+
|
|
30562
|
+
// Function to determine which data points should be visible
|
|
30563
|
+
const getVisibleData = useCallback(() => {
|
|
30564
|
+
return allChartData.filter(item => item.x >= viewDomain.x[0] && item.x <= viewDomain.x[1] && item.y >= viewDomain.y[0] && item.y <= viewDomain.y[1]);
|
|
30565
|
+
}, [allChartData, viewDomain]);
|
|
30566
|
+
|
|
30567
|
+
// Get visible data - memoized
|
|
30568
|
+
const visibleData = useMemo(() => getVisibleData(), [getVisibleData]);
|
|
30569
|
+
|
|
30570
|
+
// Calculate a new domain based on zoom level and center point - memoized
|
|
30571
|
+
const calculateDomain = useCallback((center, zoomFactor) => {
|
|
30572
|
+
// Calculate new domain size
|
|
30573
|
+
const xSize = (fullDomain.x[1] - fullDomain.x[0]) * zoomFactor;
|
|
30574
|
+
const ySize = (fullDomain.y[1] - fullDomain.y[0]) * zoomFactor;
|
|
30575
|
+
|
|
30576
|
+
// Calculate new domain
|
|
30577
|
+
return {
|
|
30578
|
+
x: [center.x - xSize / 2, center.x + xSize / 2],
|
|
30579
|
+
y: [center.y - ySize / 2, center.y + ySize / 2]
|
|
30580
|
+
};
|
|
30581
|
+
}, [fullDomain]);
|
|
30582
|
+
|
|
30583
|
+
// Rendering gradients with enhanced bubble-like appearance
|
|
30584
|
+
const renderGradients = useCallback(() => /*#__PURE__*/React$1.createElement("defs", null, /*#__PURE__*/React$1.createElement("radialGradient", {
|
|
30585
|
+
id: "topLeftGradient",
|
|
30586
|
+
cx: "25%",
|
|
30587
|
+
cy: "25%",
|
|
30588
|
+
r: "70%",
|
|
30589
|
+
fx: "20%",
|
|
30590
|
+
fy: "20%"
|
|
30591
|
+
}, /*#__PURE__*/React$1.createElement("stop", {
|
|
30592
|
+
offset: "0%",
|
|
30593
|
+
stopColor: colorPalette[0]
|
|
30594
|
+
}), /*#__PURE__*/React$1.createElement("stop", {
|
|
30595
|
+
offset: "85%",
|
|
30596
|
+
stopColor: colorPalette[1]
|
|
30597
|
+
})), /*#__PURE__*/React$1.createElement("radialGradient", {
|
|
30598
|
+
id: "topRightGradient",
|
|
30599
|
+
cx: "25%",
|
|
30600
|
+
cy: "25%",
|
|
30601
|
+
r: "70%",
|
|
30602
|
+
fx: "20%",
|
|
30603
|
+
fy: "20%"
|
|
30604
|
+
}, /*#__PURE__*/React$1.createElement("stop", {
|
|
30605
|
+
offset: "0%",
|
|
30606
|
+
stopColor: colorPalette[2]
|
|
30607
|
+
}), /*#__PURE__*/React$1.createElement("stop", {
|
|
30608
|
+
offset: "85%",
|
|
30609
|
+
stopColor: colorPalette[3]
|
|
30610
|
+
})), /*#__PURE__*/React$1.createElement("radialGradient", {
|
|
30611
|
+
id: "bottomLeftGradient",
|
|
30612
|
+
cx: "25%",
|
|
30613
|
+
cy: "25%",
|
|
30614
|
+
r: "70%",
|
|
30615
|
+
fx: "20%",
|
|
30616
|
+
fy: "20%"
|
|
30617
|
+
}, /*#__PURE__*/React$1.createElement("stop", {
|
|
30618
|
+
offset: "0%",
|
|
30619
|
+
stopColor: colorPalette[4]
|
|
30620
|
+
}), /*#__PURE__*/React$1.createElement("stop", {
|
|
30621
|
+
offset: "85%",
|
|
30622
|
+
stopColor: colorPalette[5]
|
|
30623
|
+
})), /*#__PURE__*/React$1.createElement("radialGradient", {
|
|
30624
|
+
id: "bottomRightGradient",
|
|
30625
|
+
cx: "25%",
|
|
30626
|
+
cy: "25%",
|
|
30627
|
+
r: "70%",
|
|
30628
|
+
fx: "20%",
|
|
30629
|
+
fy: "20%"
|
|
30630
|
+
}, /*#__PURE__*/React$1.createElement("stop", {
|
|
30631
|
+
offset: "0%",
|
|
30632
|
+
stopColor: colorPalette[6]
|
|
30633
|
+
}), /*#__PURE__*/React$1.createElement("stop", {
|
|
30634
|
+
offset: "85%",
|
|
30635
|
+
stopColor: colorPalette[7]
|
|
30636
|
+
})), /*#__PURE__*/React$1.createElement("filter", {
|
|
30637
|
+
id: "bubble-blur",
|
|
30638
|
+
x: "-50%",
|
|
30639
|
+
y: "-50%",
|
|
30640
|
+
width: "200%",
|
|
30641
|
+
height: "200%"
|
|
30642
|
+
}, /*#__PURE__*/React$1.createElement("feGaussianBlur", {
|
|
30643
|
+
in: "SourceGraphic",
|
|
30644
|
+
stdDeviation: "0.3"
|
|
30645
|
+
}))), [colorPalette]);
|
|
30646
|
+
|
|
30647
|
+
// Handle mouse down for dragging
|
|
30648
|
+
const handleMouseDown = useCallback(e => {
|
|
30649
|
+
if (containerRef.current?.contains(e.target)) {
|
|
30650
|
+
setIsDragging(true);
|
|
30651
|
+
setDragStart({
|
|
30652
|
+
x: e.clientX,
|
|
30653
|
+
y: e.clientY
|
|
30654
|
+
});
|
|
30655
|
+
setDomainStart({
|
|
30656
|
+
...viewDomain
|
|
30657
|
+
}); // Store current domain, not fullDomain
|
|
30658
|
+
e.preventDefault();
|
|
30659
|
+
}
|
|
30660
|
+
}, [viewDomain]); // Add viewDomain as dependency to capture current value
|
|
30661
|
+
|
|
30662
|
+
// Handle mouse move for dragging
|
|
30663
|
+
const handleMouseMove = useCallback(e => {
|
|
30664
|
+
if (!isDragging) return;
|
|
30665
|
+
const dx = e.clientX - dragStart.x;
|
|
30666
|
+
const dy = e.clientY - dragStart.y;
|
|
30667
|
+
const containerWidth = containerRef.current?.clientWidth || 800;
|
|
30668
|
+
const containerHeight = containerRef.current?.clientHeight || 600;
|
|
30669
|
+
|
|
30670
|
+
// Calculate the domain range from the domainStart (which preserves zoom level)
|
|
30671
|
+
const xRange = domainStart.x[1] - domainStart.x[0];
|
|
30672
|
+
const yRange = domainStart.y[1] - domainStart.y[0];
|
|
30673
|
+
|
|
30674
|
+
// Calculate the shift amount (negative for dx to make drag direction feel natural)
|
|
30675
|
+
const xShift = -(dx / containerWidth) * xRange * 1.5; // Multiply by 1.5 to make dragging more responsive
|
|
30676
|
+
const yShift = dy / containerHeight * yRange * 1.5; // Y is inverted in charts
|
|
30677
|
+
|
|
30678
|
+
// Create new domain values based on the domainStart (preserves zoom level)
|
|
30679
|
+
const newXDomain = [domainStart.x[0] + xShift, domainStart.x[1] + xShift];
|
|
30680
|
+
const newYDomain = [domainStart.y[0] + yShift, domainStart.y[1] + yShift];
|
|
30681
|
+
|
|
30682
|
+
// Update the domain
|
|
30683
|
+
setViewDomain({
|
|
30684
|
+
x: newXDomain,
|
|
30685
|
+
y: newYDomain
|
|
30686
|
+
});
|
|
30687
|
+
}, [isDragging, dragStart, domainStart]);
|
|
30688
|
+
|
|
30689
|
+
// Handle mouse up for dragging
|
|
30690
|
+
const handleMouseUp = useCallback(() => {
|
|
30691
|
+
setIsDragging(false);
|
|
30692
|
+
}, []);
|
|
30693
|
+
|
|
30694
|
+
// Handle zoom in
|
|
30695
|
+
const handleZoomIn = useCallback(() => {
|
|
30696
|
+
if (zoomLevel >= 400) return;
|
|
30697
|
+
const newZoomLevel = zoomLevel + 20;
|
|
30698
|
+
setZoomLevel(newZoomLevel);
|
|
30699
|
+
|
|
30700
|
+
// Calculate zoom factor (smaller factor = more zoomed in)
|
|
30701
|
+
const zoomFactor = 100 / newZoomLevel;
|
|
30702
|
+
|
|
30703
|
+
// Get current domain center
|
|
30704
|
+
const centerX = (viewDomain.x[0] + viewDomain.x[1]) / 2;
|
|
30705
|
+
const centerY = (viewDomain.y[0] + viewDomain.y[1]) / 2;
|
|
30706
|
+
|
|
30707
|
+
// Calculate new domain
|
|
30708
|
+
const newDomain = calculateDomain({
|
|
30709
|
+
x: centerX,
|
|
30710
|
+
y: centerY
|
|
30711
|
+
}, zoomFactor);
|
|
30712
|
+
|
|
30713
|
+
// Update domain
|
|
30714
|
+
setViewDomain(newDomain);
|
|
30715
|
+
}, [zoomLevel, viewDomain, calculateDomain]);
|
|
30716
|
+
|
|
30717
|
+
// Handle zoom out
|
|
30718
|
+
const handleZoomOut = useCallback(() => {
|
|
30719
|
+
if (zoomLevel <= 50) return;
|
|
30720
|
+
const newZoomLevel = zoomLevel - 20;
|
|
30721
|
+
|
|
30722
|
+
// If returning to 100%, reset to full domain
|
|
30723
|
+
if (newZoomLevel === 100) {
|
|
30724
|
+
setViewDomain({
|
|
30725
|
+
...fullDomain
|
|
30726
|
+
});
|
|
30727
|
+
setZoomLevel(100);
|
|
30728
|
+
return;
|
|
30729
|
+
}
|
|
30730
|
+
setZoomLevel(newZoomLevel);
|
|
30731
|
+
|
|
30732
|
+
// Calculate zoom factor (larger factor = more zoomed out)
|
|
30733
|
+
const zoomFactor = 100 / newZoomLevel;
|
|
30734
|
+
|
|
30735
|
+
// Get current domain center
|
|
30736
|
+
const centerX = (viewDomain.x[0] + viewDomain.x[1]) / 2;
|
|
30737
|
+
const centerY = (viewDomain.y[0] + viewDomain.y[1]) / 2;
|
|
30738
|
+
|
|
30739
|
+
// Calculate new domain size
|
|
30740
|
+
const xSize = (fullDomain.x[1] - fullDomain.x[0]) * zoomFactor;
|
|
30741
|
+
const ySize = (fullDomain.y[1] - fullDomain.y[0]) * zoomFactor;
|
|
30742
|
+
|
|
30743
|
+
// If new domain would be larger than full domain, reset to full
|
|
30744
|
+
if (xSize >= fullDomain.x[1] - fullDomain.x[0] || ySize >= fullDomain.y[1] - fullDomain.y[0]) {
|
|
30745
|
+
setViewDomain({
|
|
30746
|
+
...fullDomain
|
|
30747
|
+
});
|
|
30748
|
+
setZoomLevel(100);
|
|
30749
|
+
return;
|
|
30750
|
+
}
|
|
30751
|
+
|
|
30752
|
+
// Calculate new domain
|
|
30753
|
+
const newDomain = calculateDomain({
|
|
30754
|
+
x: centerX,
|
|
30755
|
+
y: centerY
|
|
30756
|
+
}, zoomFactor);
|
|
30757
|
+
|
|
30758
|
+
// Update domain
|
|
30759
|
+
setViewDomain(newDomain);
|
|
30760
|
+
}, [zoomLevel, viewDomain, fullDomain, calculateDomain]);
|
|
30761
|
+
|
|
30762
|
+
// Handle reset
|
|
30763
|
+
const handleReset = useCallback(() => {
|
|
30764
|
+
setZoomLevel(100);
|
|
30765
|
+
setViewDomain({
|
|
30766
|
+
...fullDomain
|
|
30767
|
+
});
|
|
30768
|
+
}, [fullDomain]);
|
|
30769
|
+
|
|
30770
|
+
// Handle mouse wheel
|
|
30771
|
+
const handleWheel = useCallback(e => {
|
|
30772
|
+
e.preventDefault();
|
|
30773
|
+
if (e.deltaY < 0) {
|
|
30774
|
+
handleZoomIn();
|
|
30347
30775
|
} else {
|
|
30348
|
-
|
|
30349
|
-
newTop = (totalSegmentsLines - completedSegments) * barHeight / 1.65;
|
|
30350
|
-
// Position the goal value just above the active chips
|
|
30351
|
-
newGoalValuePosition = newTop;
|
|
30776
|
+
handleZoomOut();
|
|
30352
30777
|
}
|
|
30353
|
-
|
|
30354
|
-
|
|
30355
|
-
|
|
30778
|
+
}, [handleZoomIn, handleZoomOut]);
|
|
30779
|
+
|
|
30780
|
+
// Memoize the visibility condition for the middle value label
|
|
30781
|
+
const isMiddleValueVisible = useMemo(() => xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] && yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1], [viewDomain, xMedian, yMedian]);
|
|
30782
|
+
|
|
30783
|
+
// Set up event listeners
|
|
30356
30784
|
useEffect(() => {
|
|
30357
|
-
|
|
30358
|
-
|
|
30359
|
-
|
|
30360
|
-
|
|
30361
|
-
|
|
30785
|
+
const container = containerRef.current;
|
|
30786
|
+
if (!container) return;
|
|
30787
|
+
container.addEventListener('wheel', handleWheel, {
|
|
30788
|
+
passive: false
|
|
30789
|
+
});
|
|
30790
|
+
container.addEventListener('mousedown', handleMouseDown);
|
|
30791
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
30792
|
+
window.addEventListener('mouseup', handleMouseUp);
|
|
30793
|
+
return () => {
|
|
30794
|
+
container.removeEventListener('wheel', handleWheel);
|
|
30795
|
+
container.removeEventListener('mousedown', handleMouseDown);
|
|
30796
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
30797
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
30798
|
+
};
|
|
30799
|
+
}, [handleWheel, handleMouseDown, handleMouseMove, handleMouseUp]);
|
|
30800
|
+
|
|
30801
|
+
// Unified arrow component with direction parameter
|
|
30802
|
+
const Arrow = _ref3 => {
|
|
30803
|
+
let {
|
|
30804
|
+
viewBox,
|
|
30805
|
+
direction
|
|
30806
|
+
} = _ref3;
|
|
30807
|
+
// Define points based on direction
|
|
30808
|
+
let points = '';
|
|
30809
|
+
switch (direction) {
|
|
30810
|
+
case 'top':
|
|
30811
|
+
points = `${viewBox.x},${viewBox.y - 10} ${viewBox.x - 5},${viewBox.y} ${viewBox.x + 5},${viewBox.y}`;
|
|
30812
|
+
break;
|
|
30813
|
+
case 'bottom':
|
|
30814
|
+
points = `${viewBox.x},${viewBox.y + viewBox.height + 10} ${viewBox.x - 5},${viewBox.y + viewBox.height} ${viewBox.x + 5},${viewBox.y + viewBox.height}`;
|
|
30815
|
+
break;
|
|
30816
|
+
case 'left':
|
|
30817
|
+
points = `${viewBox.x - 10},${viewBox.y} ${viewBox.x},${viewBox.y - 5} ${viewBox.x},${viewBox.y + 5}`;
|
|
30818
|
+
break;
|
|
30819
|
+
case 'right':
|
|
30820
|
+
points = `${viewBox.x + viewBox.width + 10},${viewBox.y} ${viewBox.x + viewBox.width},${viewBox.y - 5} ${viewBox.x + viewBox.width},${viewBox.y + 5}`;
|
|
30821
|
+
break;
|
|
30362
30822
|
}
|
|
30363
|
-
|
|
30364
|
-
|
|
30365
|
-
|
|
30823
|
+
return /*#__PURE__*/React$1.createElement("polygon", {
|
|
30824
|
+
points: points,
|
|
30825
|
+
fill: "#D0D0D0"
|
|
30826
|
+
});
|
|
30827
|
+
};
|
|
30828
|
+
|
|
30829
|
+
// Function to format currency values
|
|
30830
|
+
const formatCurrency = value => {
|
|
30831
|
+
if (Math.abs(value) >= 1000000) {
|
|
30832
|
+
return `$${(value / 1000000).toFixed(1)}M`;
|
|
30833
|
+
} else if (Math.abs(value) >= 1000) {
|
|
30834
|
+
return `$${(value / 1000).toFixed(1)}K`;
|
|
30835
|
+
}
|
|
30836
|
+
return `$${value.toFixed(1)}`;
|
|
30837
|
+
};
|
|
30838
|
+
|
|
30839
|
+
// Function to format units values
|
|
30840
|
+
const formatUnits = value => {
|
|
30841
|
+
if (Math.abs(value) >= 1000000) {
|
|
30842
|
+
return `${(value / 1000000).toFixed(1)}M`;
|
|
30843
|
+
} else if (Math.abs(value) >= 1000) {
|
|
30844
|
+
return `${(value / 1000).toFixed(1)}K`;
|
|
30845
|
+
}
|
|
30846
|
+
return `${value.toFixed(1)}`;
|
|
30847
|
+
};
|
|
30848
|
+
|
|
30849
|
+
// Function to format ROI values
|
|
30850
|
+
const formatROI = value => {
|
|
30851
|
+
return value.toFixed(1);
|
|
30852
|
+
};
|
|
30853
|
+
|
|
30854
|
+
// Format the median values for display
|
|
30855
|
+
const formattedMedianValue = useMemo(() => {
|
|
30856
|
+
const formattedX = formatROI(xMedian);
|
|
30857
|
+
const formattedY = formatUnits(yMedian);
|
|
30858
|
+
return `${formattedX}, ${formattedY}`;
|
|
30859
|
+
}, [xMedian, yMedian]);
|
|
30860
|
+
|
|
30861
|
+
// Render the component
|
|
30862
|
+
return /*#__PURE__*/React$1.createElement(BubbleChartContainer, {
|
|
30366
30863
|
width: width,
|
|
30367
30864
|
height: height,
|
|
30368
|
-
|
|
30369
|
-
|
|
30370
|
-
|
|
30371
|
-
|
|
30372
|
-
|
|
30373
|
-
|
|
30374
|
-
|
|
30375
|
-
|
|
30376
|
-
|
|
30377
|
-
|
|
30378
|
-
},
|
|
30379
|
-
|
|
30380
|
-
}, /*#__PURE__*/React$1.createElement(
|
|
30381
|
-
|
|
30382
|
-
|
|
30383
|
-
|
|
30384
|
-
|
|
30385
|
-
height:
|
|
30386
|
-
|
|
30387
|
-
|
|
30388
|
-
layout: "vertical",
|
|
30865
|
+
ref: containerRef,
|
|
30866
|
+
style: {
|
|
30867
|
+
cursor: isDragging ? 'grabbing' : 'grab'
|
|
30868
|
+
},
|
|
30869
|
+
backgroundColor: backgroundColor,
|
|
30870
|
+
"data-testid": "bubble-chart-container"
|
|
30871
|
+
}, /*#__PURE__*/React$1.createElement(HeaderContainer, {
|
|
30872
|
+
"data-testid": "header-container"
|
|
30873
|
+
}, /*#__PURE__*/React$1.createElement(ChartTitle, {
|
|
30874
|
+
"data-testid": "chart-title"
|
|
30875
|
+
}, title), /*#__PURE__*/React$1.createElement(ChartSubtitle, {
|
|
30876
|
+
"data-testid": "chart-subtitle"
|
|
30877
|
+
}, subtitle)), /*#__PURE__*/React$1.createElement(ChartContainer, {
|
|
30878
|
+
ref: scatterChartRef,
|
|
30879
|
+
"data-testid": "chart-container"
|
|
30880
|
+
}, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
30881
|
+
width: "100%",
|
|
30882
|
+
height: "100%",
|
|
30883
|
+
"data-testid": "responsive-container"
|
|
30884
|
+
}, /*#__PURE__*/React$1.createElement(ScatterChart, {
|
|
30389
30885
|
margin: {
|
|
30390
|
-
top:
|
|
30391
|
-
right:
|
|
30392
|
-
|
|
30393
|
-
|
|
30886
|
+
top: 60,
|
|
30887
|
+
right: 190,
|
|
30888
|
+
bottom: 50,
|
|
30889
|
+
left: 180
|
|
30394
30890
|
},
|
|
30395
|
-
|
|
30396
|
-
}, /*#__PURE__*/React$1.createElement(XAxis, {
|
|
30891
|
+
"data-testid": "scatter-chart"
|
|
30892
|
+
}, renderGradients(), /*#__PURE__*/React$1.createElement(XAxis, {
|
|
30397
30893
|
type: "number",
|
|
30398
|
-
|
|
30399
|
-
domain:
|
|
30894
|
+
dataKey: "x",
|
|
30895
|
+
domain: viewDomain.x,
|
|
30896
|
+
axisLine: showAxis,
|
|
30897
|
+
tickLine: showAxis,
|
|
30898
|
+
tick: showAxis ? {
|
|
30899
|
+
fontSize: 10,
|
|
30900
|
+
fontWeight: 400,
|
|
30901
|
+
fontFamily: 'Poppins'
|
|
30902
|
+
} : false,
|
|
30903
|
+
tickFormatter: value => formatUnits(value),
|
|
30904
|
+
hide: !showAxis,
|
|
30905
|
+
"data-testid": "x-axis",
|
|
30906
|
+
style: {
|
|
30907
|
+
fontSize: '10px',
|
|
30908
|
+
fontWeight: 400,
|
|
30909
|
+
fontFamily: 'Poppins'
|
|
30910
|
+
}
|
|
30400
30911
|
}), /*#__PURE__*/React$1.createElement(YAxis, {
|
|
30401
|
-
type: "
|
|
30402
|
-
|
|
30403
|
-
|
|
30404
|
-
|
|
30405
|
-
|
|
30406
|
-
|
|
30407
|
-
|
|
30912
|
+
type: "number",
|
|
30913
|
+
dataKey: "y",
|
|
30914
|
+
domain: viewDomain.y,
|
|
30915
|
+
axisLine: showAxis,
|
|
30916
|
+
tickLine: showAxis,
|
|
30917
|
+
tick: showAxis ? {
|
|
30918
|
+
fontSize: 10,
|
|
30919
|
+
fontWeight: 400,
|
|
30920
|
+
fontFamily: 'Poppins'
|
|
30921
|
+
} : false,
|
|
30922
|
+
tickFormatter: value => formatUnits(value),
|
|
30923
|
+
hide: !showAxis,
|
|
30924
|
+
"data-testid": "y-axis",
|
|
30925
|
+
style: {
|
|
30926
|
+
fontSize: '10px',
|
|
30927
|
+
fontWeight: 400,
|
|
30928
|
+
fontFamily: 'Poppins'
|
|
30929
|
+
}
|
|
30930
|
+
}), /*#__PURE__*/React$1.createElement(ZAxis, {
|
|
30931
|
+
type: "number",
|
|
30932
|
+
dataKey: "z",
|
|
30933
|
+
range: [0, 7000],
|
|
30934
|
+
domain: [0, Math.max(...data.map(item => item.size || 0))],
|
|
30935
|
+
"data-testid": "z-axis"
|
|
30936
|
+
}), /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
30937
|
+
x: xMedian,
|
|
30938
|
+
stroke: "#D0D0D0",
|
|
30939
|
+
strokeDasharray: "4 4",
|
|
30940
|
+
isFront: false,
|
|
30941
|
+
"data-testid": "reference-line-x",
|
|
30942
|
+
label: xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] ? {
|
|
30943
|
+
value: topHeader,
|
|
30944
|
+
position: "top",
|
|
30945
|
+
offset: 40,
|
|
30946
|
+
fill: '#484A4C',
|
|
30947
|
+
fontSize: 16,
|
|
30948
|
+
fontWeight: 500
|
|
30949
|
+
} : null
|
|
30950
|
+
}), xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
30951
|
+
x: xMedian,
|
|
30952
|
+
stroke: "transparent",
|
|
30953
|
+
isFront: true,
|
|
30954
|
+
label: _ref4 => {
|
|
30955
|
+
let {
|
|
30956
|
+
viewBox
|
|
30957
|
+
} = _ref4;
|
|
30958
|
+
return /*#__PURE__*/React$1.createElement(Arrow, {
|
|
30959
|
+
viewBox: viewBox,
|
|
30960
|
+
direction: "top"
|
|
30961
|
+
});
|
|
30962
|
+
}
|
|
30963
|
+
}), /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
30964
|
+
x: xMedian,
|
|
30965
|
+
stroke: "transparent",
|
|
30966
|
+
isFront: false,
|
|
30967
|
+
"data-testid": "reference-line-x-bottom",
|
|
30968
|
+
label: xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] ? {
|
|
30969
|
+
value: bottomHeader,
|
|
30970
|
+
position: "bottom",
|
|
30971
|
+
offset: 30,
|
|
30972
|
+
fill: '#484A4C',
|
|
30973
|
+
fontSize: 16,
|
|
30974
|
+
fontWeight: 500
|
|
30975
|
+
} : null
|
|
30976
|
+
}), xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
30977
|
+
x: xMedian,
|
|
30978
|
+
stroke: "transparent",
|
|
30979
|
+
isFront: true,
|
|
30980
|
+
label: _ref5 => {
|
|
30981
|
+
let {
|
|
30982
|
+
viewBox
|
|
30983
|
+
} = _ref5;
|
|
30984
|
+
return /*#__PURE__*/React$1.createElement(Arrow, {
|
|
30985
|
+
viewBox: viewBox,
|
|
30986
|
+
direction: "bottom"
|
|
30987
|
+
});
|
|
30988
|
+
}
|
|
30989
|
+
}), /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
30990
|
+
y: yMedian,
|
|
30991
|
+
stroke: "#D0D0D0",
|
|
30992
|
+
strokeDasharray: "4 4",
|
|
30993
|
+
isFront: false,
|
|
30994
|
+
"data-testid": "reference-line-y",
|
|
30995
|
+
label: yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] ? {
|
|
30996
|
+
value: leftHeader,
|
|
30997
|
+
position: "left",
|
|
30998
|
+
offset: 30,
|
|
30999
|
+
fill: '#484A4C',
|
|
31000
|
+
fontSize: 16,
|
|
31001
|
+
fontWeight: 500
|
|
31002
|
+
} : null
|
|
31003
|
+
}), yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
31004
|
+
y: yMedian,
|
|
31005
|
+
isFront: true,
|
|
31006
|
+
stroke: "transparent",
|
|
31007
|
+
label: _ref6 => {
|
|
31008
|
+
let {
|
|
31009
|
+
viewBox
|
|
31010
|
+
} = _ref6;
|
|
31011
|
+
return /*#__PURE__*/React$1.createElement(Arrow, {
|
|
31012
|
+
viewBox: viewBox,
|
|
31013
|
+
direction: "left"
|
|
31014
|
+
});
|
|
31015
|
+
}
|
|
31016
|
+
}), /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
31017
|
+
y: yMedian,
|
|
31018
|
+
stroke: "transparent",
|
|
31019
|
+
isFront: false,
|
|
31020
|
+
"data-testid": "reference-line-y-transparent",
|
|
31021
|
+
label: yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] ? {
|
|
31022
|
+
value: rightHeader,
|
|
31023
|
+
position: "right",
|
|
31024
|
+
offset: 30,
|
|
31025
|
+
fill: '#484A4C',
|
|
31026
|
+
fontSize: 16,
|
|
31027
|
+
fontWeight: 500
|
|
31028
|
+
} : null
|
|
31029
|
+
}), yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
31030
|
+
y: yMedian,
|
|
31031
|
+
isFront: true,
|
|
31032
|
+
stroke: "transparent",
|
|
31033
|
+
label: _ref7 => {
|
|
31034
|
+
let {
|
|
31035
|
+
viewBox
|
|
31036
|
+
} = _ref7;
|
|
31037
|
+
return /*#__PURE__*/React$1.createElement(Arrow, {
|
|
31038
|
+
viewBox: viewBox,
|
|
31039
|
+
direction: "right"
|
|
31040
|
+
});
|
|
31041
|
+
}
|
|
31042
|
+
}), /*#__PURE__*/React$1.createElement(Tooltip$2, {
|
|
31043
|
+
content: /*#__PURE__*/React$1.createElement(CustomTooltip, null),
|
|
31044
|
+
cursor: false,
|
|
31045
|
+
wrapperStyle: {
|
|
31046
|
+
zIndex: 9999,
|
|
31047
|
+
position: 'absolute',
|
|
31048
|
+
pointerEvents: 'auto'
|
|
30408
31049
|
},
|
|
30409
|
-
|
|
30410
|
-
|
|
30411
|
-
|
|
30412
|
-
|
|
30413
|
-
|
|
31050
|
+
allowEscapeViewBox: {
|
|
31051
|
+
x: false,
|
|
31052
|
+
y: false
|
|
31053
|
+
},
|
|
31054
|
+
"data-testid": "tooltip"
|
|
31055
|
+
}), /*#__PURE__*/React$1.createElement(Scatter, {
|
|
31056
|
+
name: "Bubble Chart",
|
|
31057
|
+
data: visibleData,
|
|
31058
|
+
shape: "circle",
|
|
31059
|
+
fill: "transparent",
|
|
31060
|
+
isAnimationActive: false,
|
|
31061
|
+
animationBegin: 0,
|
|
31062
|
+
animationDuration: 0,
|
|
31063
|
+
"data-testid": "scatter"
|
|
31064
|
+
}, visibleData.map((entry, index) => /*#__PURE__*/React$1.createElement(Cell, {
|
|
31065
|
+
key: entry.key,
|
|
31066
|
+
fill: entry.fill,
|
|
31067
|
+
stroke: "rgba(255,255,255,0.6)",
|
|
31068
|
+
strokeWidth: 1.5,
|
|
31069
|
+
filter: "url(#bubble-blur)",
|
|
31070
|
+
"data-testid": `cell-${index}`
|
|
31071
|
+
}))), isMiddleValueVisible && /*#__PURE__*/React$1.createElement(ReferenceLine, {
|
|
31072
|
+
x: xMedian,
|
|
31073
|
+
y: yMedian,
|
|
31074
|
+
stroke: "transparent",
|
|
31075
|
+
isFront: true,
|
|
31076
|
+
"data-testid": "middle-value-reference",
|
|
31077
|
+
label: _ref8 => {
|
|
31078
|
+
let {
|
|
31079
|
+
viewBox
|
|
31080
|
+
} = _ref8;
|
|
31081
|
+
// Calculate the exact position of the median point in the SVG
|
|
31082
|
+
const xPos = viewBox.x + (xMedian - viewDomain.x[0]) / (viewDomain.x[1] - viewDomain.x[0]) * viewBox.width;
|
|
31083
|
+
const yPos = viewBox.y + (1 - (yMedian - viewDomain.y[0]) / (viewDomain.y[1] - viewDomain.y[0])) * viewBox.height;
|
|
31084
|
+
return /*#__PURE__*/React$1.createElement("text", {
|
|
31085
|
+
x: xPos,
|
|
31086
|
+
y: yPos,
|
|
31087
|
+
textAnchor: "middle",
|
|
31088
|
+
dominantBaseline: "middle",
|
|
31089
|
+
fill: "#484A4C",
|
|
31090
|
+
fontSize: 16,
|
|
31091
|
+
fontWeight: 600,
|
|
31092
|
+
style: {
|
|
31093
|
+
backgroundColor: 'rgba(255, 255, 255, 0.7)',
|
|
31094
|
+
padding: '2px'
|
|
31095
|
+
}
|
|
31096
|
+
}, formattedMedianValue);
|
|
31097
|
+
}
|
|
31098
|
+
})))), /*#__PURE__*/React$1.createElement(ZoomControlsContainer, {
|
|
31099
|
+
"data-testid": "zoom-controls-container"
|
|
31100
|
+
}, /*#__PURE__*/React$1.createElement(ZoomPercentage, {
|
|
31101
|
+
"data-testid": "zoom-percentage"
|
|
31102
|
+
}, zoomLevel, "%"), /*#__PURE__*/React$1.createElement(ZoomButton, {
|
|
31103
|
+
onClick: handleZoomOut,
|
|
31104
|
+
title: "Zoom Out",
|
|
31105
|
+
"data-testid": "zoom-out-button"
|
|
31106
|
+
}, "\u2212"), /*#__PURE__*/React$1.createElement(ZoomButton, {
|
|
31107
|
+
onClick: handleZoomIn,
|
|
31108
|
+
title: "Zoom In",
|
|
31109
|
+
"data-testid": "zoom-in-button"
|
|
31110
|
+
}, "+"), /*#__PURE__*/React$1.createElement(ZoomResetButton, {
|
|
31111
|
+
onClick: handleReset,
|
|
31112
|
+
"data-testid": "zoom-reset-button"
|
|
31113
|
+
}, "Reset")));
|
|
31114
|
+
};
|
|
31115
|
+
|
|
31116
|
+
const BatteryChartContainer = styled.div`
|
|
31117
|
+
position: relative;
|
|
31118
|
+
font-family: "Poppins", sans-serif;
|
|
31119
|
+
display: grid;
|
|
31120
|
+
grid-template-columns: auto auto;
|
|
31121
|
+
grid-template-rows: auto 1fr auto;
|
|
31122
|
+
color: #212121;
|
|
31123
|
+
background-color: ${props => props.backgroundColor || 'transparent'};
|
|
31124
|
+
padding: ${props => props.containerPadding || '25px 30px 0'};
|
|
31125
|
+
width: ${props => props.width};
|
|
31126
|
+
height: ${props => props.height};
|
|
31127
|
+
`;
|
|
31128
|
+
const PanelSide = styled.div`
|
|
31129
|
+
display: flex;
|
|
31130
|
+
flex-direction: column;
|
|
31131
|
+
justify-content: space-between;
|
|
31132
|
+
`;
|
|
31133
|
+
const ProgressDetails = styled.div`
|
|
31134
|
+
display: flex;
|
|
31135
|
+
flex-direction: column;
|
|
31136
|
+
flex-grow: 1;
|
|
31137
|
+
`;
|
|
31138
|
+
const HeadingText = styled.p`
|
|
31139
|
+
grid-column: 1 / span 2;
|
|
31140
|
+
color: #212121;
|
|
31141
|
+
font-size: 18px;
|
|
31142
|
+
font-weight: 400;
|
|
31143
|
+
padding-left: 10px;
|
|
31144
|
+
margin: 0 0 8px;
|
|
31145
|
+
`;
|
|
31146
|
+
const HeadingPercentage = styled.p`
|
|
31147
|
+
color: #212121;
|
|
31148
|
+
font-size: 32px;
|
|
31149
|
+
font-weight: 500;
|
|
31150
|
+
padding-left: 10px;
|
|
31151
|
+
margin: 0;
|
|
31152
|
+
`;
|
|
31153
|
+
const ChartSide = styled.div`
|
|
31154
|
+
text-align: center;
|
|
31155
|
+
`;
|
|
31156
|
+
const ChartWrapper = styled.div`
|
|
31157
|
+
position: relative;
|
|
31158
|
+
width: 110px;
|
|
31159
|
+
`;
|
|
31160
|
+
const GoalValue = styled.div`
|
|
31161
|
+
text-align: center;
|
|
31162
|
+
font-size: 18px;
|
|
31163
|
+
color: #8B8989;
|
|
31164
|
+
line-height: 1;
|
|
31165
|
+
&.overload {
|
|
31166
|
+
position: absolute;
|
|
31167
|
+
top: ${props => props.goalValuePosition}px;
|
|
31168
|
+
left: 0;
|
|
31169
|
+
right: 0;
|
|
31170
|
+
z-index: 2;
|
|
31171
|
+
margin: 0 auto;
|
|
31172
|
+
width: 40%;
|
|
31173
|
+
display: inline;
|
|
31174
|
+
padding: 0px 8px;
|
|
31175
|
+
border: 2px solid #F2F2F2;
|
|
31176
|
+
border-bottom: none;
|
|
31177
|
+
border-radius: 6px 6px 0px 0px;
|
|
31178
|
+
background-color: white;
|
|
31179
|
+
}
|
|
31180
|
+
`;
|
|
31181
|
+
const Indicator = styled.div`
|
|
31182
|
+
position: absolute;
|
|
31183
|
+
top: ${props => props.top}px;
|
|
31184
|
+
left: 0;
|
|
31185
|
+
transform: translateY(50%);
|
|
31186
|
+
width: calc(100% + 60px);
|
|
31187
|
+
display: flex;
|
|
31188
|
+
gap: 6px;
|
|
31189
|
+
justify-content: center;
|
|
31190
|
+
padding-left: 4px;
|
|
31191
|
+
align-items: center;
|
|
31192
|
+
z-index: 1;
|
|
31193
|
+
`;
|
|
31194
|
+
const IndicatorLine = styled.div`
|
|
31195
|
+
width: 100%;
|
|
31196
|
+
height: 0;
|
|
31197
|
+
border-top: 4px dashed ${props => props.color};
|
|
31198
|
+
`;
|
|
31199
|
+
const IndicatorText = styled.span`
|
|
31200
|
+
font-size: 18px;
|
|
31201
|
+
font-weight: 400;
|
|
31202
|
+
color: ${props => props.color};
|
|
31203
|
+
`;
|
|
31204
|
+
const ProgressLegend = styled.div`
|
|
31205
|
+
margin-top: 12px;
|
|
31206
|
+
`;
|
|
31207
|
+
const LegendItem = styled.div`
|
|
31208
|
+
display: flex;
|
|
31209
|
+
gap: 4px;
|
|
31210
|
+
align-items: center;
|
|
31211
|
+
margin-bottom: 12px;
|
|
31212
|
+
`;
|
|
31213
|
+
const LegendText = styled.span`
|
|
31214
|
+
color: #8B8989;
|
|
31215
|
+
font-size: 14px;
|
|
31216
|
+
`;
|
|
31217
|
+
const LegendCube = styled.div`
|
|
31218
|
+
border-radius: 3px;
|
|
31219
|
+
width: 17px;
|
|
31220
|
+
height: 17px;
|
|
31221
|
+
background-color: ${props => props.color};
|
|
31222
|
+
`;
|
|
31223
|
+
const ProgressDescription = styled.div`
|
|
31224
|
+
color: #8B8989;
|
|
31225
|
+
font-size: 12px;
|
|
31226
|
+
font-weight: 400;
|
|
31227
|
+
margin-top: auto;
|
|
31228
|
+
`;
|
|
31229
|
+
const ProgressItem = styled.p`
|
|
31230
|
+
margin: 0 0 6px;
|
|
31231
|
+
`;
|
|
31232
|
+
const StarText = styled.span`
|
|
31233
|
+
width: 100%;
|
|
31234
|
+
color: #B1B1B1;
|
|
31235
|
+
font-size: 9px;
|
|
31236
|
+
grid-column: 1 / span 2;
|
|
31237
|
+
padding-top: 10px;
|
|
31238
|
+
`;
|
|
31239
|
+
|
|
31240
|
+
const BatteryChart = props => {
|
|
31241
|
+
const {
|
|
31242
|
+
className,
|
|
31243
|
+
containerPadding,
|
|
31244
|
+
width,
|
|
31245
|
+
height,
|
|
31246
|
+
title,
|
|
31247
|
+
color,
|
|
31248
|
+
backgroundColor,
|
|
31249
|
+
indicatorColor,
|
|
31250
|
+
noCommitment,
|
|
31251
|
+
goalAmount,
|
|
31252
|
+
currentAmount,
|
|
31253
|
+
ask,
|
|
31254
|
+
target,
|
|
31255
|
+
totalSegmentsLines,
|
|
31256
|
+
starText
|
|
31257
|
+
} = props;
|
|
31258
|
+
const [top, setTop] = useState(0);
|
|
31259
|
+
const [goalValuePosition, setGoalValuePosition] = useState(0);
|
|
31260
|
+
const [containerHeight, setContainerHeight] = useState(0); // State to store container height
|
|
31261
|
+
const containerRef = useRef(null); // Ref for BatteryChartContainer
|
|
31262
|
+
|
|
31263
|
+
// Calculate the percentage and completed segments
|
|
31264
|
+
const percentage = Math.round(currentAmount / goalAmount * 100);
|
|
31265
|
+
const completedSegments = Math.min(Math.floor(currentAmount / goalAmount * totalSegmentsLines), totalSegmentsLines);
|
|
31266
|
+
|
|
31267
|
+
// Dynamically create the data for the bar chart
|
|
31268
|
+
let barsChips = Array.from({
|
|
31269
|
+
length: totalSegmentsLines
|
|
31270
|
+
}).map((_, index) => ({
|
|
31271
|
+
name: `segment-${index}`,
|
|
31272
|
+
value: 100,
|
|
31273
|
+
isCompleted: index >= totalSegmentsLines - completedSegments,
|
|
31274
|
+
// Fill from bottom up
|
|
31275
|
+
color: index >= totalSegmentsLines - completedSegments ? color : "#e5e7eb" // Completed or remaining color
|
|
31276
|
+
}));
|
|
31277
|
+
|
|
31278
|
+
// Add 4 extra chips if currentAmount > goalAmount
|
|
31279
|
+
if (currentAmount > goalAmount && !noCommitment) {
|
|
31280
|
+
const extraSegments = 4;
|
|
31281
|
+
const extraData = Array.from({
|
|
31282
|
+
length: extraSegments
|
|
31283
|
+
}).map((_, index) => ({
|
|
31284
|
+
name: `extra-segment-${index}`,
|
|
31285
|
+
value: 100,
|
|
31286
|
+
isCompleted: true,
|
|
31287
|
+
color: "#E8F5EB"
|
|
31288
|
+
}));
|
|
31289
|
+
|
|
31290
|
+
// Prepend the extra segments to the barsChips array
|
|
31291
|
+
barsChips = [...extraData, ...barsChips];
|
|
31292
|
+
}
|
|
31293
|
+
|
|
31294
|
+
// Calculate the top position for the indicator and goal value
|
|
31295
|
+
useEffect(() => {
|
|
31296
|
+
const barHeight = containerHeight / (totalSegmentsLines + (currentAmount > goalAmount ? 4 : 0)); // Adjust for extra chips
|
|
31297
|
+
let newTop;
|
|
31298
|
+
let newGoalValuePosition;
|
|
31299
|
+
if (currentAmount > goalAmount) {
|
|
31300
|
+
// Position the indicator slightly below the top chip
|
|
31301
|
+
newTop = barHeight * 1.5; // Slightly below the 4th chip
|
|
31302
|
+
// Position the goal value just above the active chips
|
|
31303
|
+
|
|
31304
|
+
newGoalValuePosition = barHeight * 2.3;
|
|
31305
|
+
// newGoalValuePosition = (totalSegmentsLines - completedSegments + 4) * barHeight - barHeight / 2;
|
|
31306
|
+
} else {
|
|
31307
|
+
// Normal case: position the indicator above the active chips
|
|
31308
|
+
newTop = (totalSegmentsLines - completedSegments) * barHeight / 1.65;
|
|
31309
|
+
// Position the goal value just above the active chips
|
|
31310
|
+
newGoalValuePosition = newTop;
|
|
31311
|
+
}
|
|
31312
|
+
setTop(newTop);
|
|
31313
|
+
setGoalValuePosition(newGoalValuePosition);
|
|
31314
|
+
}, [completedSegments, totalSegmentsLines, currentAmount, goalAmount, containerHeight]);
|
|
31315
|
+
useEffect(() => {
|
|
31316
|
+
if (containerRef.current) {
|
|
31317
|
+
const height = containerRef.current.offsetHeight;
|
|
31318
|
+
if (height > 0) {
|
|
31319
|
+
setContainerHeight(height);
|
|
31320
|
+
}
|
|
31321
|
+
}
|
|
31322
|
+
}, [containerRef, width, height]);
|
|
31323
|
+
return /*#__PURE__*/React$1.createElement(BatteryChartContainer, {
|
|
31324
|
+
ref: containerRef,
|
|
31325
|
+
width: width,
|
|
31326
|
+
height: height,
|
|
31327
|
+
className: className,
|
|
31328
|
+
containerPadding: containerPadding,
|
|
31329
|
+
backgroundColor: backgroundColor
|
|
31330
|
+
}, /*#__PURE__*/React$1.createElement(HeadingText, null, title), /*#__PURE__*/React$1.createElement(PanelSide, null, /*#__PURE__*/React$1.createElement(ProgressDetails, null, !noCommitment && /*#__PURE__*/React$1.createElement(HeadingPercentage, null, percentage, "%"), /*#__PURE__*/React$1.createElement(ProgressDescription, null, ask && /*#__PURE__*/React$1.createElement(ProgressItem, null, "ASK: ", `$${getFormattedValue(ask, false) + getFormattedUnits(ask)}`), target && /*#__PURE__*/React$1.createElement(ProgressItem, null, "Target: ", `$${getFormattedValue(target, false) + getFormattedUnits(target)}`)), /*#__PURE__*/React$1.createElement(ProgressLegend, null, /*#__PURE__*/React$1.createElement(LegendItem, null, /*#__PURE__*/React$1.createElement(LegendCube, {
|
|
31331
|
+
color: color
|
|
31332
|
+
}), /*#__PURE__*/React$1.createElement(LegendText, null, "Spend")), !noCommitment && /*#__PURE__*/React$1.createElement(LegendItem, null, /*#__PURE__*/React$1.createElement(LegendCube, {
|
|
31333
|
+
color: "#E3E4E5"
|
|
31334
|
+
}), /*#__PURE__*/React$1.createElement(LegendText, null, "Commitment"))))), /*#__PURE__*/React$1.createElement(ChartSide, null, /*#__PURE__*/React$1.createElement(ChartWrapper, null, /*#__PURE__*/React$1.createElement(GoalValue, {
|
|
31335
|
+
className: currentAmount > goalAmount && !noCommitment ? "overload" : "",
|
|
31336
|
+
goalValuePosition: goalValuePosition
|
|
31337
|
+
}, !noCommitment ? `$${getFormattedValue(goalAmount, false) + getFormattedUnits(goalAmount)}` : `$${getFormattedValue(currentAmount, false) + getFormattedUnits(currentAmount)}`), !noCommitment && /*#__PURE__*/React$1.createElement(Indicator, {
|
|
31338
|
+
top: top
|
|
31339
|
+
}, /*#__PURE__*/React$1.createElement(IndicatorLine, {
|
|
31340
|
+
color: indicatorColor
|
|
31341
|
+
}), /*#__PURE__*/React$1.createElement(IndicatorText, {
|
|
31342
|
+
color: indicatorColor
|
|
31343
|
+
}, `$${getFormattedValue(currentAmount, false) + getFormattedUnits(currentAmount)}`)), /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
31344
|
+
height: Math.max(containerHeight - 105, 210)
|
|
31345
|
+
}, /*#__PURE__*/React$1.createElement(BarChart$1, {
|
|
31346
|
+
data: barsChips,
|
|
31347
|
+
layout: "vertical",
|
|
31348
|
+
margin: {
|
|
31349
|
+
top: 5,
|
|
31350
|
+
right: 5,
|
|
31351
|
+
left: 5,
|
|
31352
|
+
bottom: 5
|
|
31353
|
+
},
|
|
31354
|
+
barSize: 4
|
|
31355
|
+
}, /*#__PURE__*/React$1.createElement(XAxis, {
|
|
31356
|
+
type: "number",
|
|
31357
|
+
hide: true,
|
|
31358
|
+
domain: [0, 100]
|
|
31359
|
+
}), /*#__PURE__*/React$1.createElement(YAxis, {
|
|
31360
|
+
type: "category",
|
|
31361
|
+
hide: true,
|
|
31362
|
+
dataKey: "name"
|
|
31363
|
+
}), /*#__PURE__*/React$1.createElement(Bar, {
|
|
31364
|
+
dataKey: "value",
|
|
31365
|
+
background: {
|
|
31366
|
+
fill: "#f3f4f6"
|
|
31367
|
+
},
|
|
31368
|
+
radius: [8, 8, 8, 8]
|
|
31369
|
+
}, barsChips.map((entry, index) => /*#__PURE__*/React$1.createElement(Cell, {
|
|
31370
|
+
key: `cell-${index}`,
|
|
31371
|
+
fill: entry.color
|
|
31372
|
+
}))))))), starText !== "" && /*#__PURE__*/React$1.createElement(StarText, null, starText));
|
|
31373
|
+
};
|
|
31374
|
+
|
|
31375
|
+
const originalData$1 = [{
|
|
31376
|
+
label: "Vendor Selling Event: Week 28",
|
|
31377
|
+
inc_unit: 20000,
|
|
31378
|
+
inc_roi: 1.2
|
|
31379
|
+
}, {
|
|
31380
|
+
label: "Vendor Selling Event: Week 29",
|
|
31381
|
+
inc_unit: 10000,
|
|
31382
|
+
inc_roi: 1.2
|
|
31383
|
+
}, {
|
|
31384
|
+
label: "Vendor Selling Event: Week 30",
|
|
31385
|
+
inc_unit: 8000,
|
|
31386
|
+
inc_roi: 0.8
|
|
31387
|
+
}, {
|
|
31388
|
+
label: "Vendor Selling Event: Week 33",
|
|
31389
|
+
inc_unit: 12000,
|
|
31390
|
+
inc_roi: 1.1
|
|
31391
|
+
}, {
|
|
31392
|
+
label: "Vendor Selling Event: Week 36",
|
|
31393
|
+
inc_unit: 8000,
|
|
31394
|
+
inc_roi: 1.2
|
|
31395
|
+
}, {
|
|
31396
|
+
label: "Vendor Selling Event: Week 34",
|
|
31397
|
+
inc_unit: 8000,
|
|
31398
|
+
inc_roi: 0.7
|
|
31399
|
+
}, {
|
|
31400
|
+
label: "Vendor Selling Event: Week 35",
|
|
31401
|
+
inc_unit: 8000,
|
|
31402
|
+
inc_roi: 0.8
|
|
31403
|
+
}, {
|
|
31404
|
+
label: "Vendor Selling Event: Week 38",
|
|
31405
|
+
inc_unit: 9000,
|
|
31406
|
+
inc_roi: 1.1
|
|
31407
|
+
}];
|
|
31408
|
+
const dataWithIndex$1 = originalData$1.map((item, index) => ({
|
|
31409
|
+
...item,
|
|
31410
|
+
index,
|
|
31411
|
+
shortLabel: item.label.replace("Vendor Selling Event: ", "Wk ")
|
|
31412
|
+
}));
|
|
31413
|
+
const CustomizedTick$1 = ({
|
|
31414
|
+
x,
|
|
31415
|
+
y,
|
|
31416
|
+
payload
|
|
31417
|
+
}) => {
|
|
31418
|
+
const label = dataWithIndex$1[payload.value]?.label ?? "";
|
|
31419
|
+
const parts = label.replace("Vendor Selling Event: ", "").split(" ");
|
|
31420
|
+
return /*#__PURE__*/React$1.createElement("g", {
|
|
31421
|
+
transform: `translate(${x},${y})`
|
|
31422
|
+
}, /*#__PURE__*/React$1.createElement("text", {
|
|
31423
|
+
x: 0,
|
|
31424
|
+
y: 0,
|
|
31425
|
+
dy: 16,
|
|
31426
|
+
textAnchor: "middle",
|
|
31427
|
+
fill: "#212121",
|
|
31428
|
+
fontSize: 11,
|
|
31429
|
+
fontWeight: "400",
|
|
31430
|
+
fontFamily: "Poppins"
|
|
31431
|
+
}, /*#__PURE__*/React$1.createElement("tspan", {
|
|
31432
|
+
x: 0,
|
|
31433
|
+
dy: 8
|
|
31434
|
+
}, "Vendor Selling"), /*#__PURE__*/React$1.createElement("tspan", {
|
|
31435
|
+
x: 0,
|
|
31436
|
+
dy: 18
|
|
31437
|
+
}, "Event: ", parts.join(" "))));
|
|
31438
|
+
};
|
|
31439
|
+
|
|
31440
|
+
// Common chart configuration
|
|
31441
|
+
const chartMargins = {
|
|
31442
|
+
top: 15,
|
|
31443
|
+
right: 40,
|
|
31444
|
+
left: 20,
|
|
31445
|
+
bottom: 40
|
|
31446
|
+
};
|
|
31447
|
+
const SeparatedLineBarChart = () => {
|
|
31448
|
+
const [viewWindow, setViewWindow] = useState({
|
|
31449
|
+
startIndex: 0,
|
|
31450
|
+
endIndex: dataWithIndex$1.length - 1
|
|
31451
|
+
});
|
|
31452
|
+
return /*#__PURE__*/React$1.createElement("div", {
|
|
31453
|
+
style: {
|
|
31454
|
+
width: "100%",
|
|
31455
|
+
height: 700
|
|
31456
|
+
}
|
|
31457
|
+
}, /*#__PURE__*/React$1.createElement("div", {
|
|
31458
|
+
style: {
|
|
31459
|
+
height: "40%"
|
|
31460
|
+
}
|
|
31461
|
+
}, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
31462
|
+
width: "100%",
|
|
31463
|
+
height: "100%"
|
|
31464
|
+
}, /*#__PURE__*/React$1.createElement(LineChart, {
|
|
31465
|
+
data: dataWithIndex$1 // Use full dataset for alignment
|
|
31466
|
+
,
|
|
31467
|
+
margin: chartMargins
|
|
31468
|
+
}, /*#__PURE__*/React$1.createElement(CartesianGrid, {
|
|
31469
|
+
strokeDasharray: "3 3",
|
|
31470
|
+
vertical: false
|
|
31471
|
+
}), /*#__PURE__*/React$1.createElement(XAxis, {
|
|
31472
|
+
dataKey: "index",
|
|
31473
|
+
type: "number",
|
|
31474
|
+
domain: ['dataMin', 'dataMax'],
|
|
31475
|
+
padding: {
|
|
31476
|
+
left: 20,
|
|
31477
|
+
right: 20
|
|
31478
|
+
},
|
|
31479
|
+
hide: true
|
|
31480
|
+
}), /*#__PURE__*/React$1.createElement(YAxis, {
|
|
31481
|
+
domain: [0, 2],
|
|
31482
|
+
hide: true
|
|
31483
|
+
}), /*#__PURE__*/React$1.createElement(Tooltip$2, null), /*#__PURE__*/React$1.createElement(Line, {
|
|
31484
|
+
type: "monotone",
|
|
31485
|
+
dataKey: "inc_roi",
|
|
31486
|
+
stroke: "#F8CD00",
|
|
31487
|
+
strokeWidth: 2,
|
|
31488
|
+
dot: {
|
|
31489
|
+
r: 4,
|
|
31490
|
+
fill: "#F8CD00"
|
|
31491
|
+
},
|
|
31492
|
+
activeDot: false,
|
|
31493
|
+
name: "INC Sales ROI"
|
|
31494
|
+
}, /*#__PURE__*/React$1.createElement(LabelList, {
|
|
31495
|
+
dataKey: "inc_roi",
|
|
31496
|
+
position: "top",
|
|
31497
|
+
formatter: value => value.toFixed(1)
|
|
31498
|
+
}))))), /*#__PURE__*/React$1.createElement("div", {
|
|
31499
|
+
style: {
|
|
31500
|
+
height: "60%"
|
|
31501
|
+
}
|
|
31502
|
+
}, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
31503
|
+
width: "100%",
|
|
31504
|
+
height: "100%"
|
|
31505
|
+
}, /*#__PURE__*/React$1.createElement(ComposedChart, {
|
|
31506
|
+
data: dataWithIndex$1,
|
|
31507
|
+
margin: chartMargins
|
|
31508
|
+
}, /*#__PURE__*/React$1.createElement(CartesianGrid, {
|
|
31509
|
+
strokeDasharray: "3 3",
|
|
31510
|
+
vertical: false
|
|
31511
|
+
}), /*#__PURE__*/React$1.createElement(XAxis, {
|
|
31512
|
+
dataKey: "index",
|
|
31513
|
+
type: "number",
|
|
31514
|
+
domain: ['dataMin', 'dataMax'],
|
|
31515
|
+
padding: {
|
|
31516
|
+
left: 20,
|
|
31517
|
+
right: 20
|
|
31518
|
+
},
|
|
31519
|
+
tick: /*#__PURE__*/React$1.createElement(CustomizedTick$1, null),
|
|
31520
|
+
interval: 0 // Force display all ticks
|
|
31521
|
+
,
|
|
31522
|
+
height: 60,
|
|
31523
|
+
tickLine: false,
|
|
31524
|
+
ticks: dataWithIndex$1.map(item => item.index)
|
|
31525
|
+
}), /*#__PURE__*/React$1.createElement(YAxis, {
|
|
31526
|
+
tickFormatter: v => `$${v / 1000}k`,
|
|
31527
|
+
hide: true
|
|
31528
|
+
}), /*#__PURE__*/React$1.createElement(Tooltip$2, null), /*#__PURE__*/React$1.createElement(Bar, {
|
|
31529
|
+
dataKey: "inc_unit",
|
|
31530
|
+
fill: "#CCDCDD",
|
|
31531
|
+
gap: "4px",
|
|
31532
|
+
borderRadius: [4, 4, 0, 8],
|
|
31533
|
+
barSize: 40,
|
|
31534
|
+
name: "INC Sales"
|
|
31535
|
+
}, /*#__PURE__*/React$1.createElement(LabelList, {
|
|
31536
|
+
dataKey: "inc_unit",
|
|
31537
|
+
position: "top",
|
|
31538
|
+
formatter: value => `$${value / 1000}k`,
|
|
31539
|
+
fill: "#212121",
|
|
31540
|
+
fontSize: 12,
|
|
31541
|
+
fontWeight: "400",
|
|
31542
|
+
fontFamily: "Poppins"
|
|
31543
|
+
})), /*#__PURE__*/React$1.createElement(Brush, {
|
|
31544
|
+
dataKey: "index",
|
|
31545
|
+
height: 30,
|
|
31546
|
+
stroke: "#212121",
|
|
31547
|
+
startIndex: viewWindow.startIndex,
|
|
31548
|
+
endIndex: viewWindow.endIndex,
|
|
31549
|
+
onChange: e => {
|
|
31550
|
+
setViewWindow({
|
|
31551
|
+
startIndex: e.startIndex ?? 0,
|
|
31552
|
+
endIndex: e.endIndex ?? dataWithIndex$1.length - 1
|
|
31553
|
+
});
|
|
31554
|
+
},
|
|
31555
|
+
travellerWidth: 12
|
|
31556
|
+
})), /*#__PURE__*/React$1.createElement("div", {
|
|
31557
|
+
style: {
|
|
31558
|
+
marginTop: "-28px"
|
|
31559
|
+
}
|
|
31560
|
+
}, /*#__PURE__*/React$1.createElement(PerformanceAnalyticsLegend, {
|
|
31561
|
+
legendData: [{
|
|
31562
|
+
iconColor: "#CCDCDD",
|
|
31563
|
+
iconType: "Square",
|
|
31564
|
+
title: "INC Sales"
|
|
31565
|
+
}, {
|
|
31566
|
+
iconColor: "#F8CD00",
|
|
31567
|
+
iconType: "LegendUnionIcon",
|
|
31568
|
+
title: "INC Sales ROI"
|
|
31569
|
+
}]
|
|
31570
|
+
})))));
|
|
31571
|
+
};
|
|
31572
|
+
|
|
31573
|
+
const originalData = [{
|
|
31574
|
+
label: "Vendor Selling Event: Week 28",
|
|
31575
|
+
inc_unit: 20000
|
|
31576
|
+
}, {
|
|
31577
|
+
label: "Vendor Selling Event: Week 29",
|
|
31578
|
+
inc_unit: 10000
|
|
31579
|
+
}, {
|
|
31580
|
+
label: "Vendor Selling Event: Week 30",
|
|
31581
|
+
inc_unit: 8000
|
|
31582
|
+
}, {
|
|
31583
|
+
label: "Vendor Selling Event: Week 33",
|
|
31584
|
+
inc_unit: 12000
|
|
31585
|
+
}, {
|
|
31586
|
+
label: "Vendor Selling Event: Week 36",
|
|
31587
|
+
inc_unit: 8000
|
|
31588
|
+
}, {
|
|
31589
|
+
label: "Vendor Selling Event: Week 34",
|
|
31590
|
+
inc_unit: 8000
|
|
31591
|
+
}, {
|
|
31592
|
+
label: "Vendor Selling Event: Week 35",
|
|
31593
|
+
inc_unit: 8000
|
|
31594
|
+
}, {
|
|
31595
|
+
label: "Vendor Selling Event: Week 38",
|
|
31596
|
+
inc_unit: 9000
|
|
31597
|
+
}];
|
|
31598
|
+
|
|
31599
|
+
// Adding index and shortLabel to original data
|
|
31600
|
+
const dataWithIndex = originalData.map((item, index) => ({
|
|
31601
|
+
...item,
|
|
31602
|
+
index,
|
|
31603
|
+
shortLabel: item.label.replace("Vendor Selling Event: ", "Wk ")
|
|
31604
|
+
}));
|
|
31605
|
+
const CustomizedTick = ({
|
|
31606
|
+
x,
|
|
31607
|
+
y,
|
|
31608
|
+
payload
|
|
31609
|
+
}) => {
|
|
31610
|
+
const label = dataWithIndex[payload.value]?.label ?? "";
|
|
31611
|
+
const parts = label.replace("Vendor Selling Event: ", "").split(" ");
|
|
31612
|
+
return /*#__PURE__*/React$1.createElement("g", {
|
|
31613
|
+
transform: `translate(${x},${y})`
|
|
31614
|
+
}, /*#__PURE__*/React$1.createElement("text", {
|
|
31615
|
+
x: 0,
|
|
31616
|
+
y: 0,
|
|
31617
|
+
dy: 16,
|
|
31618
|
+
textAnchor: "middle",
|
|
31619
|
+
fill: "#212121",
|
|
31620
|
+
fontSize: 11,
|
|
31621
|
+
fontWeight: "400",
|
|
31622
|
+
fontFamily: "Poppins"
|
|
31623
|
+
}, /*#__PURE__*/React$1.createElement("tspan", {
|
|
31624
|
+
x: 0,
|
|
31625
|
+
dy: 8
|
|
31626
|
+
}, "Vendor Selling"), /*#__PURE__*/React$1.createElement("tspan", {
|
|
31627
|
+
x: 0,
|
|
31628
|
+
dy: 18
|
|
31629
|
+
}, "Event: ", parts.join(" "))));
|
|
31630
|
+
};
|
|
31631
|
+
const SingleChart = () => {
|
|
31632
|
+
const [startIndex, setStartIndex] = useState(0);
|
|
31633
|
+
const [endIndex, setEndIndex] = useState(dataWithIndex.length - 1);
|
|
31634
|
+
dataWithIndex.slice(startIndex, endIndex + 1);
|
|
31635
|
+
return /*#__PURE__*/React$1.createElement("div", {
|
|
31636
|
+
style: {
|
|
31637
|
+
width: "100%",
|
|
31638
|
+
height: 600
|
|
31639
|
+
}
|
|
31640
|
+
}, /*#__PURE__*/React$1.createElement("div", {
|
|
31641
|
+
style: {
|
|
31642
|
+
height: "100%"
|
|
31643
|
+
}
|
|
31644
|
+
}, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
31645
|
+
width: "100%",
|
|
31646
|
+
height: "100%"
|
|
31647
|
+
}, /*#__PURE__*/React$1.createElement(ComposedChart, {
|
|
31648
|
+
data: dataWithIndex,
|
|
31649
|
+
margin: {
|
|
31650
|
+
top: 40,
|
|
31651
|
+
right: 40,
|
|
31652
|
+
left: 20,
|
|
31653
|
+
bottom: 40
|
|
31654
|
+
}
|
|
31655
|
+
}, /*#__PURE__*/React$1.createElement(CartesianGrid, {
|
|
31656
|
+
strokeDasharray: "3 3",
|
|
31657
|
+
vertical: false
|
|
31658
|
+
}), /*#__PURE__*/React$1.createElement(XAxis, {
|
|
31659
|
+
dataKey: "index",
|
|
31660
|
+
tick: /*#__PURE__*/React$1.createElement(CustomizedTick, null),
|
|
31661
|
+
interval: 0,
|
|
31662
|
+
height: 60,
|
|
31663
|
+
padding: {
|
|
31664
|
+
left: 20,
|
|
31665
|
+
right: 20
|
|
31666
|
+
},
|
|
31667
|
+
tickLine: false
|
|
31668
|
+
}), /*#__PURE__*/React$1.createElement(YAxis, {
|
|
31669
|
+
tickFormatter: v => `$${v / 1000}k`,
|
|
31670
|
+
hide: true
|
|
31671
|
+
}), /*#__PURE__*/React$1.createElement(Tooltip$2, null), /*#__PURE__*/React$1.createElement(Bar, {
|
|
31672
|
+
dataKey: "inc_unit",
|
|
31673
|
+
fill: "#CCDCDD",
|
|
31674
|
+
gap: "4px",
|
|
31675
|
+
borderRadius: [4, 4, 0, 8],
|
|
31676
|
+
barSize: 40,
|
|
31677
|
+
name: "INC Sales"
|
|
31678
|
+
}, /*#__PURE__*/React$1.createElement(LabelList, {
|
|
31679
|
+
dataKey: "inc_unit",
|
|
31680
|
+
position: "top",
|
|
31681
|
+
formatter: value => `$${value / 1000}k`,
|
|
31682
|
+
fill: "#212121",
|
|
31683
|
+
fontSize: 12,
|
|
31684
|
+
fontWeight: "400",
|
|
31685
|
+
fontFamily: "Poppins"
|
|
31686
|
+
})), /*#__PURE__*/React$1.createElement(Brush, {
|
|
31687
|
+
dataKey: "index",
|
|
31688
|
+
height: 30,
|
|
31689
|
+
stroke: "#212121",
|
|
31690
|
+
startIndex: startIndex,
|
|
31691
|
+
endIndex: endIndex,
|
|
31692
|
+
onChange: e => {
|
|
31693
|
+
setStartIndex(e.startIndex ?? 0);
|
|
31694
|
+
setEndIndex(e.endIndex ?? dataWithIndex.length - 1);
|
|
31695
|
+
},
|
|
31696
|
+
travellerWidth: 12
|
|
31697
|
+
})), /*#__PURE__*/React$1.createElement(PerformanceAnalyticsLegend, {
|
|
31698
|
+
legendData: [{
|
|
31699
|
+
iconColor: "#CCDCDD",
|
|
31700
|
+
iconType: "Square",
|
|
31701
|
+
title: "INC Units"
|
|
31702
|
+
}]
|
|
31703
|
+
}))));
|
|
31704
|
+
};
|
|
31705
|
+
|
|
31706
|
+
styled.div`
|
|
31707
|
+
display: flex;
|
|
31708
|
+
gap: 28px;
|
|
31709
|
+
@media (max-width: 1536px) {
|
|
31710
|
+
gap: 20px;
|
|
31711
|
+
}
|
|
31712
|
+
@media (max-width: 1366px) {
|
|
31713
|
+
gap: 17px;
|
|
31714
|
+
}
|
|
31715
|
+
`;
|
|
31716
|
+
const ButtonsControlsContainer = styled.div`
|
|
31717
|
+
display: flex;
|
|
31718
|
+
font: ${props => props.fontSize?.toString().concat('', 'px Poppins, sans-serif')};
|
|
31719
|
+
margin: 0;
|
|
31720
|
+
--highlight-width: auto;
|
|
31721
|
+
--highlight-x-pos: 0;
|
|
31722
|
+
-webkit-font-smoothing: antialiased;
|
|
31723
|
+
-moz-osx-font-smoothing: grayscale;
|
|
31724
|
+
float: left;
|
|
31725
|
+
|
|
31726
|
+
&:not(:first-of-type) {
|
|
31727
|
+
padding-left: 40px;
|
|
31728
|
+
@media (max-width: 1536px) {
|
|
31729
|
+
padding-left: 35px;
|
|
31730
|
+
}
|
|
31731
|
+
@media (max-width: 1366px) {
|
|
31732
|
+
padding-left: 24px;
|
|
31733
|
+
}
|
|
31734
|
+
}
|
|
31735
|
+
`;
|
|
31736
|
+
const Controls = styled.div`
|
|
31737
|
+
display: inline-flex;
|
|
31738
|
+
justify-content: space-between;
|
|
31739
|
+
background: #f2f2f2;
|
|
31740
|
+
border-radius: ${props => props.controlradius.toString().concat('', 'px')}; //12px
|
|
31741
|
+
// max-width: 500px; //use this to limit max lenght of the control
|
|
31742
|
+
padding: 6px;
|
|
31743
|
+
gap: ${props => props.gap};
|
|
31744
|
+
overflow: hidden;
|
|
31745
|
+
position: relative;
|
|
31746
|
+
&.controls::before {
|
|
31747
|
+
content: "";
|
|
31748
|
+
color: #212121;
|
|
31749
|
+
background: #FFFFFF;
|
|
31750
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|
31751
|
+
border-radius: ${props => props.segmentradius.toString().concat('', 'px')};
|
|
31752
|
+
width: var(--highlight-width);
|
|
31753
|
+
transform: translateX(var(--highlight-x-pos));
|
|
31754
|
+
position: absolute;
|
|
31755
|
+
top: 3px;
|
|
31756
|
+
bottom: 3px;
|
|
31757
|
+
left: 0;
|
|
31758
|
+
z-index: 0;
|
|
31759
|
+
}
|
|
31760
|
+
&.controls.ready::before {
|
|
31761
|
+
transition: transform 0.3s ease, width 0.3s ease;
|
|
31762
|
+
}
|
|
31763
|
+
`;
|
|
31764
|
+
const ControlsInput = styled.input`
|
|
31765
|
+
opacity: 0;
|
|
31766
|
+
margin: 0;
|
|
31767
|
+
top: 0;
|
|
31768
|
+
right: 0;
|
|
31769
|
+
bottom: 0;
|
|
31770
|
+
left: 0;
|
|
31771
|
+
position: absolute;
|
|
31772
|
+
width: 100%;
|
|
31773
|
+
cursor: pointer;
|
|
31774
|
+
height: 100%;
|
|
31775
|
+
`;
|
|
31776
|
+
const Segment = styled.div`
|
|
31777
|
+
/* width: 100%; uncomment for each segment to have matching width */
|
|
31778
|
+
width: 50%;
|
|
31779
|
+
min-width: ${props => props.segmentwidth.toString().concat('', 'px')}; //120px;
|
|
31780
|
+
position: relative;
|
|
31781
|
+
text-align: center;
|
|
31782
|
+
z-index: 1;
|
|
31783
|
+
`;
|
|
31784
|
+
const SegmentLabel = styled.label`
|
|
31785
|
+
cursor: pointer;
|
|
31786
|
+
display: block;
|
|
31787
|
+
padding: 0 6px;
|
|
31788
|
+
transition: color 0.5s ease;
|
|
31789
|
+
&.active {
|
|
31790
|
+
color: ${props => props.selectedtextcolor};
|
|
31791
|
+
}
|
|
31792
|
+
&.inactive {
|
|
31793
|
+
color: ${props => props.unselectedtextcolor};
|
|
31794
|
+
}
|
|
31795
|
+
`;
|
|
31796
|
+
|
|
31797
|
+
/* eslint-disable react/require-default-props */
|
|
31798
|
+
|
|
31799
|
+
/* SegmentedButton */
|
|
31800
|
+
const SegmentedButton = props => {
|
|
31801
|
+
const {
|
|
31802
|
+
name,
|
|
31803
|
+
options,
|
|
31804
|
+
width,
|
|
31805
|
+
height,
|
|
31806
|
+
controlradius,
|
|
31807
|
+
segmentradius,
|
|
31808
|
+
fontSize,
|
|
31809
|
+
selectedsegmentcolor,
|
|
31810
|
+
selectedtextcolor,
|
|
31811
|
+
unselectedtextcolor,
|
|
31812
|
+
defaultIndex,
|
|
31813
|
+
onClick,
|
|
31814
|
+
gap
|
|
31815
|
+
} = props;
|
|
31816
|
+
const [activeIndex, setActiveIndex] = useState(defaultIndex);
|
|
31817
|
+
const controlRef = useRef();
|
|
31818
|
+
const componentReady = useRef();
|
|
31819
|
+
const optionsRef = options?.map((item, i) => ({
|
|
31820
|
+
...item,
|
|
31821
|
+
id: i,
|
|
31822
|
+
ref: useRef()
|
|
31823
|
+
}));
|
|
31824
|
+
|
|
31825
|
+
// Determine when the component is "ready"
|
|
31826
|
+
useEffect(() => {
|
|
31827
|
+
componentReady.current = true;
|
|
31828
|
+
}, []);
|
|
31829
|
+
useEffect(() => {
|
|
31830
|
+
if (defaultIndex >= 0 && defaultIndex < options?.length) {
|
|
31831
|
+
setActiveIndex(defaultIndex);
|
|
31832
|
+
}
|
|
31833
|
+
}, [defaultIndex]);
|
|
31834
|
+
useEffect(() => {
|
|
31835
|
+
const activeSegmentRef = optionsRef[activeIndex].ref;
|
|
31836
|
+
const {
|
|
31837
|
+
offsetWidth,
|
|
31838
|
+
offsetLeft
|
|
31839
|
+
} = activeSegmentRef.current;
|
|
31840
|
+
const {
|
|
31841
|
+
style
|
|
31842
|
+
} = controlRef.current;
|
|
31843
|
+
style.setProperty('--highlight-width', `${offsetWidth}px`);
|
|
31844
|
+
style.setProperty('--highlight-x-pos', `${offsetLeft}px`);
|
|
31845
|
+
}, [activeIndex, controlRef, optionsRef]);
|
|
31846
|
+
const onInputChangeHandler = (value, index) => {
|
|
31847
|
+
setActiveIndex(index);
|
|
31848
|
+
onClick({
|
|
31849
|
+
index,
|
|
31850
|
+
value
|
|
31851
|
+
});
|
|
31852
|
+
};
|
|
31853
|
+
let segmentwidth = 120;
|
|
31854
|
+
if (options && options.length > 0 && width && width > 0) {
|
|
31855
|
+
segmentwidth = width / options.length;
|
|
31856
|
+
}
|
|
31857
|
+
return /*#__PURE__*/React$1.createElement(ButtonsControlsContainer, {
|
|
31858
|
+
fontSize: fontSize,
|
|
31859
|
+
ref: controlRef
|
|
31860
|
+
}, /*#__PURE__*/React$1.createElement(Controls, {
|
|
31861
|
+
id: "Controls",
|
|
31862
|
+
selectedsegmentcolor: selectedsegmentcolor,
|
|
31863
|
+
segmentradius: segmentradius,
|
|
31864
|
+
gap: gap,
|
|
31865
|
+
controlradius: controlradius,
|
|
31866
|
+
segmentwidth: segmentwidth,
|
|
31867
|
+
className: `controls ${componentReady.current ? 'ready' : 'idle'}`
|
|
31868
|
+
}, optionsRef?.map((item, i) => /*#__PURE__*/React$1.createElement(Segment, {
|
|
31869
|
+
id: "Segment",
|
|
31870
|
+
key: item.id,
|
|
31871
|
+
selectedsegmentcolor: selectedsegmentcolor,
|
|
31872
|
+
controlradius: controlradius,
|
|
31873
|
+
segmentwidth: segmentwidth,
|
|
31874
|
+
className: `${activeIndex === i ? 'active' : 'inactive'}`,
|
|
31875
|
+
ref: item.ref
|
|
31876
|
+
}, /*#__PURE__*/React$1.createElement(ControlsInput, {
|
|
31877
|
+
type: "radio",
|
|
31878
|
+
value: item.value,
|
|
31879
|
+
id: item.id,
|
|
31880
|
+
name: name,
|
|
31881
|
+
onChange: () => onInputChangeHandler(item.value, item.id),
|
|
31882
|
+
checked: i === activeIndex
|
|
31883
|
+
}), /*#__PURE__*/React$1.createElement(SegmentLabel, {
|
|
31884
|
+
id: "SegmentLabel",
|
|
31885
|
+
selectedtextcolor: selectedtextcolor,
|
|
31886
|
+
unselectedtextcolor: unselectedtextcolor,
|
|
31887
|
+
segmentheight: height / 5,
|
|
31888
|
+
className: `${activeIndex === i ? 'active' : 'inactive'} `,
|
|
31889
|
+
htmlFor: item.value
|
|
31890
|
+
}, item.value)))));
|
|
31891
|
+
};
|
|
31892
|
+
SegmentedButton.propTypes = {
|
|
31893
|
+
name: PropTypes.string,
|
|
31894
|
+
options: PropTypes.arrayOf(PropTypes.shape({
|
|
31895
|
+
value: PropTypes.string
|
|
31896
|
+
})),
|
|
31897
|
+
width: PropTypes.number,
|
|
31898
|
+
height: PropTypes.number,
|
|
31899
|
+
controlradius: PropTypes.number,
|
|
31900
|
+
segmentradius: PropTypes.number,
|
|
31901
|
+
gap: PropTypes.string,
|
|
31902
|
+
fontSize: PropTypes.number,
|
|
31903
|
+
selectedsegmentcolor: PropTypes.string,
|
|
31904
|
+
selectedtextcolor: PropTypes.string,
|
|
31905
|
+
unselectedtextcolor: PropTypes.string,
|
|
31906
|
+
defaultIndex: PropTypes.number,
|
|
31907
|
+
onClick: PropTypes.func
|
|
31908
|
+
};
|
|
31909
|
+
SegmentedButton.defaultProps = {
|
|
31910
|
+
name: '',
|
|
31911
|
+
options: [{
|
|
31912
|
+
value: '4 w'
|
|
31913
|
+
}, {
|
|
31914
|
+
value: '8 w'
|
|
31915
|
+
}, {
|
|
31916
|
+
value: '13 w'
|
|
31917
|
+
}],
|
|
31918
|
+
width: 120,
|
|
31919
|
+
height: 40,
|
|
31920
|
+
controlradius: 8,
|
|
31921
|
+
segmentradius: 8,
|
|
31922
|
+
gap: '0px',
|
|
31923
|
+
fontSize: 14,
|
|
31924
|
+
selectedsegmentcolor: '#3a9df9',
|
|
31925
|
+
selectedtextcolor: '#212121',
|
|
31926
|
+
unselectedtextcolor: 'black',
|
|
31927
|
+
defaultIndex: 0,
|
|
31928
|
+
onClick: () => {}
|
|
31929
|
+
};
|
|
31930
|
+
|
|
31931
|
+
var css_248z = ".BarLine {\r\n font-family: sans-serif;\r\n text-align: center;\r\n }\r\n \r\n /* Make brush background darker */\r\n /* .recharts-brush .recharts-brush-slide {\r\n fill: #a52a2a !important;\r\n stroke: none;\r\n }\r\n \r\n /* Style draggable handles (travellers) */\r\n /* .recharts-brush-traveller {\r\n fill: limegreen !important; /* bright green like in the image */\r\n /* cursor: ew-resize;\r\n } */\r\n */\r\n \r\n /* Optional: center grip arrows (you can fake it with CSS) */\r\n /* .recharts-brush .recharts-brush-traveller > rect {\r\n rx: 2;\r\n ry: 2;\r\n width: 6;\r\n fill: #a52a2a !important; /* dark gray */\r\n /* } */ */\r\n */\r\n \r\n /* Remove tick labels if needed */\r\n .recharts-brush .recharts-layer text {\r\n display: none;\r\n }\r\n ";
|
|
31932
|
+
styleInject(css_248z);
|
|
31933
|
+
|
|
31934
|
+
function InnerBarChart() {
|
|
31935
|
+
const data = [{
|
|
31936
|
+
week: "Week 28",
|
|
31937
|
+
total: 20000,
|
|
31938
|
+
actual: 4000
|
|
31939
|
+
}, {
|
|
31940
|
+
week: "Week 29",
|
|
31941
|
+
total: 10000,
|
|
31942
|
+
actual: 8000
|
|
31943
|
+
}, {
|
|
31944
|
+
week: "Week 30",
|
|
31945
|
+
total: 8000,
|
|
31946
|
+
actual: 950
|
|
31947
|
+
}, {
|
|
31948
|
+
week: "Week 33",
|
|
31949
|
+
total: 12000,
|
|
31950
|
+
actual: 1000
|
|
31951
|
+
}, {
|
|
31952
|
+
week: "Week 36",
|
|
31953
|
+
total: 16000,
|
|
31954
|
+
actual: 13000
|
|
31955
|
+
}, {
|
|
31956
|
+
week: "Week 34",
|
|
31957
|
+
total: 30000,
|
|
31958
|
+
actual: 3000
|
|
31959
|
+
}, {
|
|
31960
|
+
week: "Week 35",
|
|
31961
|
+
total: 8000,
|
|
31962
|
+
actual: 950
|
|
31963
|
+
}, {
|
|
31964
|
+
week: "Week 37",
|
|
31965
|
+
total: 9000,
|
|
31966
|
+
actual: 3000
|
|
31967
|
+
}];
|
|
31968
|
+
const originalData = [{
|
|
31969
|
+
label: "Vendor Selling Event: Week 28",
|
|
31970
|
+
inc_unit: 20000,
|
|
31971
|
+
inc_roi: 1.2
|
|
31972
|
+
}, {
|
|
31973
|
+
label: "Vendor Selling Event: Week 29",
|
|
31974
|
+
inc_unit: 10000,
|
|
31975
|
+
inc_roi: 1.2
|
|
31976
|
+
}, {
|
|
31977
|
+
label: "Vendor Selling Event: Week 30",
|
|
31978
|
+
inc_unit: 8000,
|
|
31979
|
+
inc_roi: 0.8
|
|
31980
|
+
}, {
|
|
31981
|
+
label: "Vendor Selling Event: Week 33",
|
|
31982
|
+
inc_unit: 12000,
|
|
31983
|
+
inc_roi: 1.1
|
|
31984
|
+
}, {
|
|
31985
|
+
label: "Vendor Selling Event: Week 36",
|
|
31986
|
+
inc_unit: 8000,
|
|
31987
|
+
inc_roi: 1.2
|
|
31988
|
+
}, {
|
|
31989
|
+
label: "Vendor Selling Event: Week 34",
|
|
31990
|
+
inc_unit: 8000,
|
|
31991
|
+
inc_roi: 0.7
|
|
31992
|
+
}, {
|
|
31993
|
+
label: "Vendor Selling Event: Week 35",
|
|
31994
|
+
inc_unit: 8000,
|
|
31995
|
+
inc_roi: 0.8
|
|
31996
|
+
}, {
|
|
31997
|
+
label: "Vendor Selling Event: Week 38",
|
|
31998
|
+
inc_unit: 9000,
|
|
31999
|
+
inc_roi: 1.1
|
|
32000
|
+
}];
|
|
32001
|
+
const format = v => v >= 1000 ? `${v / 1000}K` : v;
|
|
32002
|
+
const CustomBarLabel = ({
|
|
32003
|
+
x,
|
|
32004
|
+
y,
|
|
32005
|
+
width,
|
|
32006
|
+
payload
|
|
32007
|
+
}) => {
|
|
32008
|
+
if (!payload || typeof payload.total === "undefined") {
|
|
32009
|
+
console.error("Invalid payload:", payload);
|
|
32010
|
+
return null;
|
|
32011
|
+
}
|
|
32012
|
+
const centerX = x + width / 2;
|
|
32013
|
+
return /*#__PURE__*/React$1.createElement("text", {
|
|
32014
|
+
x: centerX,
|
|
32015
|
+
y: Math.max(y - 8, 10),
|
|
32016
|
+
textAnchor: "middle",
|
|
32017
|
+
fill: "black"
|
|
32018
|
+
}, format(payload.total));
|
|
32019
|
+
};
|
|
32020
|
+
const BarWithInner = props => {
|
|
32021
|
+
const {
|
|
32022
|
+
x,
|
|
32023
|
+
y,
|
|
32024
|
+
width,
|
|
32025
|
+
height,
|
|
32026
|
+
payload
|
|
32027
|
+
} = props;
|
|
32028
|
+
const totalHeight = height;
|
|
32029
|
+
const actualRatio = payload.actual / payload.total;
|
|
32030
|
+
const innerHeight = totalHeight * actualRatio;
|
|
32031
|
+
const innerY = y + (totalHeight - innerHeight);
|
|
32032
|
+
return /*#__PURE__*/React$1.createElement("g", null, /*#__PURE__*/React$1.createElement("rect", {
|
|
32033
|
+
x: x,
|
|
32034
|
+
y: y,
|
|
32035
|
+
width: width,
|
|
32036
|
+
height: height,
|
|
32037
|
+
fill: "#d0e6ea",
|
|
32038
|
+
rx: 4,
|
|
32039
|
+
ry: 4
|
|
32040
|
+
}), /*#__PURE__*/React$1.createElement("text", {
|
|
32041
|
+
x: x + width / 2,
|
|
32042
|
+
y: y - 8,
|
|
32043
|
+
textAnchor: "middle",
|
|
32044
|
+
fontSize: 11,
|
|
32045
|
+
fontWeight: 400,
|
|
32046
|
+
fontFamily: "Poppins",
|
|
32047
|
+
fill: "#212121"
|
|
32048
|
+
}, format(payload.total)), /*#__PURE__*/React$1.createElement("rect", {
|
|
32049
|
+
x: x + width * 0.2,
|
|
32050
|
+
y: innerY,
|
|
32051
|
+
width: width * 0.6,
|
|
32052
|
+
height: innerHeight,
|
|
32053
|
+
fill: "#07575b",
|
|
32054
|
+
rx: 2,
|
|
32055
|
+
ry: 2
|
|
32056
|
+
}), innerHeight > 16 && /*#__PURE__*/React$1.createElement("text", {
|
|
32057
|
+
x: x + width / 2,
|
|
32058
|
+
y: innerY - 6,
|
|
32059
|
+
textAnchor: "middle",
|
|
32060
|
+
fontSize: 11,
|
|
32061
|
+
fontWeight: 400,
|
|
32062
|
+
fontFamily: "Poppins",
|
|
32063
|
+
fill: "#212121"
|
|
32064
|
+
}, format(payload.actual)));
|
|
32065
|
+
};
|
|
32066
|
+
const CustomTooltip = ({
|
|
32067
|
+
active,
|
|
32068
|
+
payload,
|
|
32069
|
+
label
|
|
32070
|
+
}) => {
|
|
32071
|
+
if (!active || !payload || !payload.length) return null;
|
|
32072
|
+
const data = payload[0].payload;
|
|
32073
|
+
return /*#__PURE__*/React$1.createElement("div", {
|
|
32074
|
+
style: {
|
|
32075
|
+
background: "white",
|
|
32076
|
+
border: "1px solid #ccc",
|
|
32077
|
+
padding: "10px",
|
|
32078
|
+
borderRadius: "8px",
|
|
32079
|
+
fontSize: "14px"
|
|
32080
|
+
}
|
|
32081
|
+
}, /*#__PURE__*/React$1.createElement("strong", null, label), /*#__PURE__*/React$1.createElement("div", null, "Actual: ", format(data.actual)), /*#__PURE__*/React$1.createElement("div", null, "Total: ", format(data.total)));
|
|
32082
|
+
};
|
|
32083
|
+
const dataWithIndex = originalData.map((item, index) => ({
|
|
32084
|
+
...item,
|
|
32085
|
+
index,
|
|
32086
|
+
shortLabel: item.label.replace("Vendor Selling Event: ", "Wk ")
|
|
32087
|
+
}));
|
|
32088
|
+
const CustomizedTick = ({
|
|
32089
|
+
x,
|
|
32090
|
+
y,
|
|
32091
|
+
payload
|
|
32092
|
+
}) => {
|
|
32093
|
+
const label = dataWithIndex[payload.value]?.label ?? "";
|
|
32094
|
+
const parts = label.replace("Vendor Selling Event: ", "").split(" ");
|
|
32095
|
+
return /*#__PURE__*/React$1.createElement("g", {
|
|
32096
|
+
transform: `translate(${x},${y})`
|
|
32097
|
+
}, /*#__PURE__*/React$1.createElement("text", {
|
|
32098
|
+
x: 0,
|
|
32099
|
+
y: 0,
|
|
32100
|
+
dy: 16,
|
|
32101
|
+
textAnchor: "middle",
|
|
32102
|
+
fill: "#212121",
|
|
32103
|
+
fontSize: 11,
|
|
32104
|
+
fontWeight: "400",
|
|
32105
|
+
fontFamily: "Poppins"
|
|
32106
|
+
}, /*#__PURE__*/React$1.createElement("tspan", {
|
|
32107
|
+
x: 0,
|
|
32108
|
+
dy: 8
|
|
32109
|
+
}, "Vendor Selling"), /*#__PURE__*/React$1.createElement("tspan", {
|
|
32110
|
+
x: 0,
|
|
32111
|
+
dy: 18
|
|
32112
|
+
}, "Event: ", parts.join(" "))));
|
|
32113
|
+
};
|
|
32114
|
+
return /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
|
|
32115
|
+
width: "100%",
|
|
32116
|
+
height: 400
|
|
32117
|
+
}, /*#__PURE__*/React$1.createElement(BarChart$1, {
|
|
32118
|
+
data: data,
|
|
32119
|
+
margin: {
|
|
32120
|
+
top: 20,
|
|
32121
|
+
right: 30,
|
|
32122
|
+
left: 20,
|
|
32123
|
+
bottom: 10
|
|
32124
|
+
}
|
|
32125
|
+
}, /*#__PURE__*/React$1.createElement(CartesianGrid, {
|
|
32126
|
+
strokeDasharray: "3 3",
|
|
32127
|
+
vertical: false
|
|
32128
|
+
}), /*#__PURE__*/React$1.createElement(XAxis, {
|
|
32129
|
+
dataKey: "week",
|
|
32130
|
+
tick: /*#__PURE__*/React$1.createElement(CustomizedTick, null)
|
|
32131
|
+
}), /*#__PURE__*/React$1.createElement(YAxis, {
|
|
32132
|
+
type: "number",
|
|
32133
|
+
domain: [0, "dataMax + 2000"],
|
|
32134
|
+
hide: true
|
|
32135
|
+
}), /*#__PURE__*/React$1.createElement(Tooltip$2, {
|
|
32136
|
+
content: /*#__PURE__*/React$1.createElement(CustomTooltip, null)
|
|
32137
|
+
}), /*#__PURE__*/React$1.createElement(Brush, {
|
|
32138
|
+
height: 30,
|
|
32139
|
+
travellerWidth: 10,
|
|
32140
|
+
startIndex: 1,
|
|
32141
|
+
endIndex: 5,
|
|
32142
|
+
y: 369
|
|
32143
|
+
}), /*#__PURE__*/React$1.createElement(Bar, {
|
|
32144
|
+
dataKey: "total",
|
|
32145
|
+
shape: /*#__PURE__*/React$1.createElement(BarWithInner, null),
|
|
32146
|
+
label: /*#__PURE__*/React$1.createElement(CustomBarLabel, null),
|
|
32147
|
+
barSize: 30
|
|
32148
|
+
})));
|
|
32149
|
+
}
|
|
32150
|
+
|
|
32151
|
+
styled.div`
|
|
32152
|
+
font-family: sans-serif;
|
|
32153
|
+
text-align: center;
|
|
32154
|
+
`;
|
|
32155
|
+
styled.div`
|
|
32156
|
+
height: 25%;
|
|
32157
|
+
`;
|
|
32158
|
+
styled.div`
|
|
32159
|
+
height: 75%;
|
|
32160
|
+
`;
|
|
32161
|
+
styled.div`
|
|
32162
|
+
height: 100%;
|
|
32163
|
+
display: flex;
|
|
32164
|
+
flex-direction: column;
|
|
32165
|
+
background-color: white;
|
|
32166
|
+
`;
|
|
32167
|
+
const Container = styled.div`
|
|
32168
|
+
width: 100%;
|
|
32169
|
+
height: 100%;
|
|
32170
|
+
display: flex;
|
|
32171
|
+
flex-direction: column;
|
|
32172
|
+
#Segment {
|
|
32173
|
+
width: auto;
|
|
32174
|
+
white-space: nowrap;
|
|
32175
|
+
font-size: 14px;
|
|
32176
|
+
font-weight: 500;
|
|
32177
|
+
font-family: "Poppins"
|
|
32178
|
+
}
|
|
32179
|
+
`;
|
|
32180
|
+
/* Make brush background darker */
|
|
32181
|
+
/* .recharts-brush .recharts-brush-slide {
|
|
32182
|
+
fill: #a52a2a !important;
|
|
32183
|
+
stroke: none;
|
|
32184
|
+
}
|
|
32185
|
+
|
|
32186
|
+
/* Style draggable handles (travellers) */
|
|
32187
|
+
/* .recharts-brush-traveller {
|
|
32188
|
+
fill: limegreen !important; /* bright green like in the image */
|
|
32189
|
+
/* cursor: ew-resize;
|
|
32190
|
+
} */
|
|
32191
|
+
|
|
32192
|
+
/* Optional: center grip arrows (you can fake it with CSS) */
|
|
32193
|
+
/* .recharts-brush .recharts-brush-traveller > rect {
|
|
32194
|
+
rx: 2;
|
|
32195
|
+
ry: 2;
|
|
32196
|
+
width: 6;
|
|
32197
|
+
fill: #a52a2a !important; /* dark gray */
|
|
32198
|
+
/* } */
|
|
32199
|
+
|
|
32200
|
+
/* Remove tick labels if needed */
|
|
32201
|
+
// .recharts-brush .recharts-layer text {
|
|
32202
|
+
// display: none;
|
|
32203
|
+
// }
|
|
32204
|
+
|
|
32205
|
+
const BrushChart = () => {
|
|
32206
|
+
const segmentedbuttonOptions = ["New Shoppers & Repeaters", "INC Sales & ROI", "INC Units", "Basket Lift"];
|
|
32207
|
+
const [selectedOption, setSelectedOption] = useState(segmentedbuttonOptions[0]);
|
|
32208
|
+
return /*#__PURE__*/React$1.createElement(Container, null, /*#__PURE__*/React$1.createElement(SegmentedButton, {
|
|
32209
|
+
gap: '8px',
|
|
32210
|
+
options: segmentedbuttonOptions.map(value => ({
|
|
32211
|
+
value
|
|
32212
|
+
})),
|
|
32213
|
+
onClick: _ref => {
|
|
32214
|
+
let {
|
|
32215
|
+
value
|
|
32216
|
+
} = _ref;
|
|
32217
|
+
return setSelectedOption(value);
|
|
32218
|
+
}
|
|
32219
|
+
}), selectedOption === "New Shoppers & Repeaters" && /*#__PURE__*/React$1.createElement(InnerBarChart, null), selectedOption === "INC Sales & ROI" && /*#__PURE__*/React$1.createElement(SeparatedLineBarChart, null), selectedOption === "INC Units" && /*#__PURE__*/React$1.createElement(SingleChart, null), selectedOption === "Basket Lift" && /*#__PURE__*/React$1.createElement(SingleChart, null));
|
|
30414
32220
|
};
|
|
30415
32221
|
|
|
30416
|
-
export { AreaChart, BannerEventBoxList, BarChart, BarChartsByWeeks, BatteryChart, BreakdownPanel, Button, CollapseHeader, DialogOverlay, DoubleBarSingleLine, DoublePanelDataRow, EventDetailsCard, EventList, FilterPanel, Heatmap, IconButton, LinkButton, LinnerDataBox, MarketShareDescription, OneColumnContainer, PerformanceAnalyticsLegend, PieChart, PopupCharts, QuickFilter, ReportTable, TabMenu, TopToggleList, TotalDoughnutChart, TotalHorizontalCharts };
|
|
32222
|
+
export { AreaChart, BannerEventBoxList, BarChart, BarChartsByWeeks, BatteryChart, BreakdownPanel, BrushChart, BubbleChart, Button, CollapseHeader, DialogOverlay, DoubleBarSingleLine, DoublePanelDataRow, EventDetailsCard, EventList, FilterPanel, Heatmap, IconButton, LinkButton, LinnerDataBox, MarketShareDescription, OneColumnContainer, PerformanceAnalyticsLegend, PieChart, PopupCharts, QuickFilter, ReportTable, TabMenu, TopToggleList, TotalDoughnutChart, TotalHorizontalCharts };
|
|
30417
32223
|
//# sourceMappingURL=index.esm.js.map
|