UNPKG

@lobehub/charts

Version:

React modern charts components built on recharts

199 lines (194 loc) 7.99 kB
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } import { differenceInCalendarDays, eachDayOfInterval, endOfYear, formatISO, getDay, getMonth, nextDay, parseISO, startOfYear, subWeeks } from 'date-fns'; import { isOnSeverSide } from "./index"; export var DEFAULT_MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; export var DEFAULT_LABELS = { legend: { less: 'Less', more: 'More' }, months: DEFAULT_MONTH_LABELS, tooltip: '{{count}} activities on {{date}}', totalCount: '{{count}} activities in {{year}}', weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] }; var fillHoles = function fillHoles(activities) { if (activities.length === 0) { return []; } var calendar = new Map(activities.map(function (a) { return [a.date, a]; })); var firstActivity = activities[0]; var lastActivity = activities.at(-1); return eachDayOfInterval({ end: parseISO(lastActivity.date), start: parseISO(firstActivity.date) }).map(function (day) { var date = formatISO(day, { representation: 'date' }); if (calendar.has(date)) { return calendar.get(date); } return { count: 0, date: date, level: 0 }; }); }; var calcTextDimensions = function calcTextDimensions(text, fontSize) { if (isOnSeverSide) return; if (fontSize < 1) { throw new RangeError('fontSize must be positive'); } if (text.length === 0) { return { height: 0, width: 0 }; } var namespace = 'http://www.w3.org/2000/svg'; var svg = document.createElementNS(namespace, 'svg'); svg.style.position = 'absolute'; svg.style.visibility = 'hidden'; svg.style.fontFamily = window.getComputedStyle(document.body).fontFamily; svg.style.fontSize = "".concat(fontSize, "px"); var textNode = document.createElementNS(namespace, 'text'); textNode.textContent = text; svg.append(textNode); document.body.append(svg); var boundingBox = textNode.getBBox(); svg.remove(); return { height: boundingBox.height, width: boundingBox.width }; }; export var groupByWeeks = function groupByWeeks(activities) { var weekStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; if (activities.length === 0) { return []; } var normalizedActivities = fillHoles(activities); // Determine the first date of the calendar. If the first date is not the // set start weekday, the selected weekday one week earlier is used. var firstActivity = normalizedActivities[0]; var firstDate = parseISO(firstActivity.date); var firstCalendarDate = getDay(firstDate) === weekStart ? firstDate : subWeeks(nextDay(firstDate, weekStart), 1); // To correctly group activities by week, it is necessary to left-pad the list // because the first date might not be set start weekday. var paddedActivities = [].concat(_toConsumableArray(Array.from({ length: differenceInCalendarDays(firstDate, firstCalendarDate) }).fill(null)), _toConsumableArray(normalizedActivities)); var numberOfWeeks = Math.ceil(paddedActivities.length / 7); // Finally, group activities by week return Array.from({ length: numberOfWeeks }).fill(null).map(function (_, weekIndex) { return paddedActivities.slice(weekIndex * 7, weekIndex * 7 + 7); }); }; export var getMonthLabels = function getMonthLabels(weeks) { var monthNames = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_MONTH_LABELS; return weeks.reduce(function (labels, week, weekIndex) { var firstActivity = week.filter(Boolean).find(function (activity) { return activity !== undefined; }); if (!firstActivity) { throw new Error("Unexpected error: Week ".concat(weekIndex + 1, " is empty: [").concat(week, "].")); } var month = monthNames[getMonth(parseISO(firstActivity.date))]; if (!month) { var monthName = new Date(firstActivity.date).toLocaleString('en-US', { month: 'short' }); throw new Error("Unexpected error: undefined month label for ".concat(monthName, ".")); } var prevLabel = labels.at(-1); if (weekIndex === 0 || !prevLabel || prevLabel.label !== month) { return [].concat(_toConsumableArray(labels), [{ label: month, weekIndex: weekIndex }]); } return labels; }, []).filter(function (_ref, index, labels) { var weekIndex = _ref.weekIndex; // Labels should only be shown if there is "enough" space (data). // This is a naive implementation that does not take the block size, // font size, etc. into account. var minWeeks = 3; // Skip the first month label if there is not enough space to the next one. if (index === 0) { return labels[1] && labels[1].weekIndex - weekIndex >= minWeeks; } // Skip the last month label if there is not enough data in that month // to avoid overflowing the calendar on the right. if (index === labels.length - 1) { return weeks.slice(weekIndex).length >= minWeeks; } return true; }); }; export var generateEmptyData = function generateEmptyData() { var year = new Date().getFullYear(); var days = eachDayOfInterval({ end: new Date(year, 11, 31), start: new Date(year, 0, 1) }); return days.map(function (date) { return { count: 0, date: formatISO(date, { representation: 'date' }), level: 0 }; }); }; export var generateTestData = function generateTestData(args) { var _args$interval; var maxCount = 20; var maxLevel = args.maxLevel ? Math.max(1, args.maxLevel) : 4; var now = new Date(); var days = eachDayOfInterval((_args$interval = args.interval) !== null && _args$interval !== void 0 ? _args$interval : { end: endOfYear(now), start: startOfYear(now) }); return days.map(function (date) { // The random activity count is shifted by up to 80% towards zero. var c = Math.round(Math.random() * maxCount - Math.random() * (0.8 * maxCount)); var count = Math.max(0, c); var level = Math.ceil(count / maxCount * maxLevel); return { count: count, date: formatISO(date, { representation: 'date' }), level: level }; }); }; export var maxWeekdayLabelLength = function maxWeekdayLabelLength(firstWeek, weekStart, labels, fontSize) { if (isOnSeverSide) return 0; if (labels.length !== 7) { throw new Error('Exactly 7 labels, one for each weekday must be passed.'); } return firstWeek.reduce(function (maxLength, _, index) { if (index % 2 !== 0) { var dayIndex = (index + weekStart) % 7; var label = labels[dayIndex]; // @ts-ignore var curLength = Math.ceil(calcTextDimensions(label, fontSize).width); return Math.max(maxLength, curLength); } return maxLength; }, 0); };