@lobehub/charts 1.1.0 → 1.3.0
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/README.md +1 -0
- package/es/BarChart/index.js +0 -1
- package/es/DataBars/CategoryBar.d.ts +13 -0
- package/es/DataBars/CategoryBar.js +191 -0
- package/es/DataBars/DeltaBar.d.ts +13 -0
- package/es/DataBars/DeltaBar.js +115 -0
- package/es/DataBars/MarkerBar.d.ts +16 -0
- package/es/DataBars/MarkerBar.js +91 -0
- package/es/DataBars/ProgressBar.d.ts +12 -0
- package/es/DataBars/ProgressBar.js +68 -0
- package/es/DataBars/index.d.ts +4 -0
- package/es/DataBars/index.js +4 -0
- package/es/DataBars/styles.d.ts +7 -0
- package/es/DataBars/styles.js +14 -0
- package/es/Heatmaps/Calendar.d.ts +18 -0
- package/es/Heatmaps/Calendar.js +67 -0
- package/es/Heatmaps/ChartLabels.d.ts +15 -0
- package/es/Heatmaps/ChartLabels.js +50 -0
- package/es/Heatmaps/Footer.d.ts +22 -0
- package/es/Heatmaps/Footer.js +60 -0
- package/es/Heatmaps/index.d.ts +28 -0
- package/es/Heatmaps/index.js +181 -0
- package/es/Heatmaps/styles.d.ts +7 -0
- package/es/Heatmaps/styles.js +14 -0
- package/es/{components/Legend → Legend}/index.js +1 -1
- package/es/common/ChartLegend.js +1 -1
- package/es/hooks/useOnWindowResize.js +2 -1
- package/es/hooks/usePrefersReducedMotion.d.ts +1 -0
- package/es/hooks/usePrefersReducedMotion.js +23 -0
- package/es/index.d.ts +3 -1
- package/es/index.js +3 -1
- package/es/types.d.ts +30 -0
- package/es/types.js +8 -1
- package/es/utils/calendar.d.ts +29 -0
- package/es/utils/calendar.js +194 -0
- package/es/utils/index.d.ts +2 -0
- package/es/utils/index.js +26 -0
- package/es/utils/theme.d.ts +2 -0
- package/es/utils/theme.js +49 -0
- package/package.json +7 -4
- /package/es/{components/Legend → Legend}/LegendItem.d.ts +0 -0
- /package/es/{components/Legend → Legend}/LegendItem.js +0 -0
- /package/es/{components/Legend → Legend}/ScrollButton.d.ts +0 -0
- /package/es/{components/Legend → Legend}/ScrollButton.js +0 -0
- /package/es/{components/Legend → Legend}/index.d.ts +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
2
|
+
import { differenceInCalendarDays, eachDayOfInterval, endOfYear, formatISO, getDay, getMonth, nextDay, parseISO, startOfYear, subWeeks } from 'date-fns';
|
|
3
|
+
import { isOnSeverSide } from "./index";
|
|
4
|
+
export var DEFAULT_MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
5
|
+
export var DEFAULT_LABELS = {
|
|
6
|
+
legend: {
|
|
7
|
+
less: 'Less',
|
|
8
|
+
more: 'More'
|
|
9
|
+
},
|
|
10
|
+
months: DEFAULT_MONTH_LABELS,
|
|
11
|
+
tooltip: '{{count}} activities on {{date}}',
|
|
12
|
+
totalCount: '{{count}} activities in {{year}}',
|
|
13
|
+
weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
|
14
|
+
};
|
|
15
|
+
var fillHoles = function fillHoles(activities) {
|
|
16
|
+
if (activities.length === 0) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
var calendar = new Map(activities.map(function (a) {
|
|
20
|
+
return [a.date, a];
|
|
21
|
+
}));
|
|
22
|
+
var firstActivity = activities[0];
|
|
23
|
+
var lastActivity = activities.at(-1);
|
|
24
|
+
return eachDayOfInterval({
|
|
25
|
+
end: parseISO(lastActivity.date),
|
|
26
|
+
start: parseISO(firstActivity.date)
|
|
27
|
+
}).map(function (day) {
|
|
28
|
+
var date = formatISO(day, {
|
|
29
|
+
representation: 'date'
|
|
30
|
+
});
|
|
31
|
+
if (calendar.has(date)) {
|
|
32
|
+
return calendar.get(date);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
count: 0,
|
|
36
|
+
date: date,
|
|
37
|
+
level: 0
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
var calcTextDimensions = function calcTextDimensions(text, fontSize) {
|
|
42
|
+
if (isOnSeverSide) return;
|
|
43
|
+
if (fontSize < 1) {
|
|
44
|
+
throw new RangeError('fontSize must be positive');
|
|
45
|
+
}
|
|
46
|
+
if (text.length === 0) {
|
|
47
|
+
return {
|
|
48
|
+
height: 0,
|
|
49
|
+
width: 0
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
var namespace = 'http://www.w3.org/2000/svg';
|
|
53
|
+
var svg = document.createElementNS(namespace, 'svg');
|
|
54
|
+
svg.style.position = 'absolute';
|
|
55
|
+
svg.style.visibility = 'hidden';
|
|
56
|
+
svg.style.fontFamily = window.getComputedStyle(document.body).fontFamily;
|
|
57
|
+
svg.style.fontSize = "".concat(fontSize, "px");
|
|
58
|
+
var textNode = document.createElementNS(namespace, 'text');
|
|
59
|
+
textNode.textContent = text;
|
|
60
|
+
svg.append(textNode);
|
|
61
|
+
document.body.append(svg);
|
|
62
|
+
var boundingBox = textNode.getBBox();
|
|
63
|
+
svg.remove();
|
|
64
|
+
return {
|
|
65
|
+
height: boundingBox.height,
|
|
66
|
+
width: boundingBox.width
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export var groupByWeeks = function groupByWeeks(activities) {
|
|
70
|
+
var weekStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
71
|
+
if (activities.length === 0) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
var normalizedActivities = fillHoles(activities);
|
|
75
|
+
|
|
76
|
+
// Determine the first date of the calendar. If the first date is not the
|
|
77
|
+
// set start weekday, the selected weekday one week earlier is used.
|
|
78
|
+
var firstActivity = normalizedActivities[0];
|
|
79
|
+
var firstDate = parseISO(firstActivity.date);
|
|
80
|
+
var firstCalendarDate = getDay(firstDate) === weekStart ? firstDate : subWeeks(nextDay(firstDate, weekStart), 1);
|
|
81
|
+
|
|
82
|
+
// To correctly group activities by week, it is necessary to left-pad the list
|
|
83
|
+
// because the first date might not be set start weekday.
|
|
84
|
+
var paddedActivities = [].concat(_toConsumableArray(Array.from({
|
|
85
|
+
length: differenceInCalendarDays(firstDate, firstCalendarDate)
|
|
86
|
+
}).fill(null)), _toConsumableArray(normalizedActivities));
|
|
87
|
+
var numberOfWeeks = Math.ceil(paddedActivities.length / 7);
|
|
88
|
+
|
|
89
|
+
// Finally, group activities by week
|
|
90
|
+
return Array.from({
|
|
91
|
+
length: numberOfWeeks
|
|
92
|
+
}).fill(null).map(function (_, weekIndex) {
|
|
93
|
+
return paddedActivities.slice(weekIndex * 7, weekIndex * 7 + 7);
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
export var getMonthLabels = function getMonthLabels(weeks) {
|
|
97
|
+
var monthNames = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_MONTH_LABELS;
|
|
98
|
+
return weeks.reduce(function (labels, week, weekIndex) {
|
|
99
|
+
var firstActivity = week.filter(Boolean).find(function (activity) {
|
|
100
|
+
return activity !== undefined;
|
|
101
|
+
});
|
|
102
|
+
if (!firstActivity) {
|
|
103
|
+
throw new Error("Unexpected error: Week ".concat(weekIndex + 1, " is empty: [").concat(week, "]."));
|
|
104
|
+
}
|
|
105
|
+
var month = monthNames[getMonth(parseISO(firstActivity.date))];
|
|
106
|
+
if (!month) {
|
|
107
|
+
var monthName = new Date(firstActivity.date).toLocaleString('en-US', {
|
|
108
|
+
month: 'short'
|
|
109
|
+
});
|
|
110
|
+
throw new Error("Unexpected error: undefined month label for ".concat(monthName, "."));
|
|
111
|
+
}
|
|
112
|
+
var prevLabel = labels.at(-1);
|
|
113
|
+
if (weekIndex === 0 || !prevLabel || prevLabel.label !== month) {
|
|
114
|
+
return [].concat(_toConsumableArray(labels), [{
|
|
115
|
+
label: month,
|
|
116
|
+
weekIndex: weekIndex
|
|
117
|
+
}]);
|
|
118
|
+
}
|
|
119
|
+
return labels;
|
|
120
|
+
}, []).filter(function (_ref, index, labels) {
|
|
121
|
+
var weekIndex = _ref.weekIndex;
|
|
122
|
+
// Labels should only be shown if there is "enough" space (data).
|
|
123
|
+
// This is a naive implementation that does not take the block size,
|
|
124
|
+
// font size, etc. into account.
|
|
125
|
+
var minWeeks = 3;
|
|
126
|
+
|
|
127
|
+
// Skip the first month label if there is not enough space to the next one.
|
|
128
|
+
if (index === 0) {
|
|
129
|
+
return labels[1] && labels[1].weekIndex - weekIndex >= minWeeks;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Skip the last month label if there is not enough data in that month
|
|
133
|
+
// to avoid overflowing the calendar on the right.
|
|
134
|
+
if (index === labels.length - 1) {
|
|
135
|
+
return weeks.slice(weekIndex).length >= minWeeks;
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
export var generateEmptyData = function generateEmptyData() {
|
|
141
|
+
var year = new Date().getFullYear();
|
|
142
|
+
var days = eachDayOfInterval({
|
|
143
|
+
end: new Date(year, 11, 31),
|
|
144
|
+
start: new Date(year, 0, 1)
|
|
145
|
+
});
|
|
146
|
+
return days.map(function (date) {
|
|
147
|
+
return {
|
|
148
|
+
count: 0,
|
|
149
|
+
date: formatISO(date, {
|
|
150
|
+
representation: 'date'
|
|
151
|
+
}),
|
|
152
|
+
level: 0
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
export var generateTestData = function generateTestData(args) {
|
|
157
|
+
var _args$interval;
|
|
158
|
+
var maxCount = 20;
|
|
159
|
+
var maxLevel = args.maxLevel ? Math.max(1, args.maxLevel) : 4;
|
|
160
|
+
var now = new Date();
|
|
161
|
+
var days = eachDayOfInterval((_args$interval = args.interval) !== null && _args$interval !== void 0 ? _args$interval : {
|
|
162
|
+
end: endOfYear(now),
|
|
163
|
+
start: startOfYear(now)
|
|
164
|
+
});
|
|
165
|
+
return days.map(function (date) {
|
|
166
|
+
// The random activity count is shifted by up to 80% towards zero.
|
|
167
|
+
var c = Math.round(Math.random() * maxCount - Math.random() * (0.8 * maxCount));
|
|
168
|
+
var count = Math.max(0, c);
|
|
169
|
+
var level = Math.ceil(count / maxCount * maxLevel);
|
|
170
|
+
return {
|
|
171
|
+
count: count,
|
|
172
|
+
date: formatISO(date, {
|
|
173
|
+
representation: 'date'
|
|
174
|
+
}),
|
|
175
|
+
level: level
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
export var maxWeekdayLabelLength = function maxWeekdayLabelLength(firstWeek, weekStart, labels, fontSize) {
|
|
180
|
+
if (isOnSeverSide) return 0;
|
|
181
|
+
if (labels.length !== 7) {
|
|
182
|
+
throw new Error('Exactly 7 labels, one for each weekday must be passed.');
|
|
183
|
+
}
|
|
184
|
+
return firstWeek.reduce(function (maxLength, _, index) {
|
|
185
|
+
if (index % 2 !== 0) {
|
|
186
|
+
var dayIndex = (index + weekStart) % 7;
|
|
187
|
+
var label = labels[dayIndex];
|
|
188
|
+
// @ts-ignore
|
|
189
|
+
var curLength = Math.ceil(calcTextDimensions(label, fontSize).width);
|
|
190
|
+
return Math.max(maxLength, curLength);
|
|
191
|
+
}
|
|
192
|
+
return maxLength;
|
|
193
|
+
}, 0);
|
|
194
|
+
};
|
package/es/utils/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ValueFormatter } from "../types";
|
|
2
2
|
export declare const defaultValueFormatter: ValueFormatter;
|
|
3
3
|
export declare const sumNumericArray: (arr: number[]) => number;
|
|
4
|
+
export declare const isOnSeverSide: boolean;
|
|
5
|
+
export declare const mapInputsToDeltaType: (deltaType: string, isIncreasePositive: boolean) => string;
|
package/es/utils/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DeltaTypes } from "../types";
|
|
1
2
|
export var defaultValueFormatter = function defaultValueFormatter(value) {
|
|
2
3
|
return value.toString();
|
|
3
4
|
};
|
|
@@ -5,4 +6,29 @@ export var sumNumericArray = function sumNumericArray(arr) {
|
|
|
5
6
|
return arr.reduce(function (prefixSum, num) {
|
|
6
7
|
return prefixSum + num;
|
|
7
8
|
}, 0);
|
|
9
|
+
};
|
|
10
|
+
export var isOnSeverSide = typeof document === 'undefined' || typeof window === 'undefined';
|
|
11
|
+
export var mapInputsToDeltaType = function mapInputsToDeltaType(deltaType, isIncreasePositive) {
|
|
12
|
+
if (isIncreasePositive || deltaType === DeltaTypes.Unchanged) {
|
|
13
|
+
return deltaType;
|
|
14
|
+
}
|
|
15
|
+
switch (deltaType) {
|
|
16
|
+
case DeltaTypes.Increase:
|
|
17
|
+
{
|
|
18
|
+
return DeltaTypes.Decrease;
|
|
19
|
+
}
|
|
20
|
+
case DeltaTypes.ModerateIncrease:
|
|
21
|
+
{
|
|
22
|
+
return DeltaTypes.ModerateDecrease;
|
|
23
|
+
}
|
|
24
|
+
case DeltaTypes.Decrease:
|
|
25
|
+
{
|
|
26
|
+
return DeltaTypes.Increase;
|
|
27
|
+
}
|
|
28
|
+
case DeltaTypes.ModerateDecrease:
|
|
29
|
+
{
|
|
30
|
+
return DeltaTypes.ModerateIncrease;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return '';
|
|
8
34
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import _typeof from "@babel/runtime/helpers/esm/typeof";
|
|
2
|
+
import chroma from 'chroma-js';
|
|
3
|
+
var isstringScale = function isstringScale(colors, size) {
|
|
4
|
+
var invalidstring = colors.find(function (color) {
|
|
5
|
+
return !chroma.valid(color);
|
|
6
|
+
});
|
|
7
|
+
if (invalidstring) {
|
|
8
|
+
throw new Error("Invalid color \"".concat(String(invalidstring), "\" passed. All CSS color formats are accepted."));
|
|
9
|
+
}
|
|
10
|
+
return colors.length === size;
|
|
11
|
+
};
|
|
12
|
+
var createstringScale = function createstringScale(colors, size) {
|
|
13
|
+
return chroma.scale(colors).mode('lch').colors(size);
|
|
14
|
+
};
|
|
15
|
+
var validateTheme = function validateTheme(input, size) {
|
|
16
|
+
if (_typeof(input) !== 'object' || input === undefined) {
|
|
17
|
+
throw new Error("The theme object must contain at least 2 or ".concat(size, " colors respectively."));
|
|
18
|
+
}
|
|
19
|
+
if (input) {
|
|
20
|
+
var length = input.length;
|
|
21
|
+
if (length !== 2 && length !== size) {
|
|
22
|
+
throw new Error("theme must contain exactly 2 or ".concat(size, " colors, ").concat(length, " passed."));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var createDefaultTheme = function createDefaultTheme(size) {
|
|
27
|
+
return createstringScale(['hsl(0, 0%, 20%)', 'hsl(0, 0%, 92%)'], size);
|
|
28
|
+
};
|
|
29
|
+
export function createTheme(input) {
|
|
30
|
+
var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
|
|
31
|
+
var defaultTheme = createDefaultTheme(size);
|
|
32
|
+
if (input) {
|
|
33
|
+
validateTheme(input, size);
|
|
34
|
+
var theme = input !== null && input !== void 0 ? input : defaultTheme;
|
|
35
|
+
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
return isstringScale(theme, size) ? theme : createstringScale(theme, size);
|
|
38
|
+
}
|
|
39
|
+
return defaultTheme;
|
|
40
|
+
}
|
|
41
|
+
export var convertAlphaToSolid = function convertAlphaToSolid(foreground, background) {
|
|
42
|
+
var fgColor = chroma(foreground);
|
|
43
|
+
var bgColor = chroma(background);
|
|
44
|
+
var alpha = fgColor.alpha();
|
|
45
|
+
var alphaComplement = 1 - alpha;
|
|
46
|
+
var mixedColor = [fgColor.get('rgb.r') * alpha + bgColor.get('rgb.r') * alphaComplement, fgColor.get('rgb.g') * alpha + bgColor.get('rgb.g') * alphaComplement, fgColor.get('rgb.b') * alpha + bgColor.get('rgb.b') * alphaComplement];
|
|
47
|
+
var resultColor = chroma(mixedColor);
|
|
48
|
+
return resultColor.hex();
|
|
49
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/charts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "React modern charts components built on recharts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lobehub",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@babel/runtime": "^7.24.8",
|
|
71
|
+
"date-fns": "^3.6.0",
|
|
71
72
|
"polished": "^4.3.1",
|
|
72
|
-
"react-layout-kit": "^1.9.0",
|
|
73
73
|
"recharts": "^2.12.7"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"@lobehub/lint": "^1.24.3",
|
|
79
79
|
"@lobehub/ui": "^1.146.8",
|
|
80
80
|
"@testing-library/react": "^14.3.1",
|
|
81
|
+
"@types/chroma-js": "^2.4.4",
|
|
81
82
|
"@types/pangu": "^4.0.2",
|
|
82
83
|
"@types/query-string": "^6.3.0",
|
|
83
84
|
"@types/react": "18.2.40",
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
"dumi-theme-lobehub": "^1.8.1",
|
|
92
93
|
"eslint": "^8.57.0",
|
|
93
94
|
"father": "4.3.1",
|
|
94
|
-
"husky": "
|
|
95
|
+
"husky": "9.0.11",
|
|
95
96
|
"jsdom": "^23.2.0",
|
|
96
97
|
"lint-staged": "^15.2.7",
|
|
97
98
|
"prettier": "^3.3.3",
|
|
@@ -109,9 +110,11 @@
|
|
|
109
110
|
"ahooks": ">=3",
|
|
110
111
|
"antd": ">=5.13.0",
|
|
111
112
|
"antd-style": ">=3",
|
|
113
|
+
"chroma-js": ">=2",
|
|
112
114
|
"lucide-react": ">=0.396.0",
|
|
113
115
|
"react": ">=18",
|
|
114
|
-
"react-dom": ">=18"
|
|
116
|
+
"react-dom": ">=18",
|
|
117
|
+
"react-layout-kit": ">=1"
|
|
115
118
|
},
|
|
116
119
|
"publishConfig": {
|
|
117
120
|
"access": "public",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|