由于郑州最近的雨夹雪天气,已经一周没有骑行了,实在憋得不行,给自己找点事做,今天中午下班时更新了一下博客
Update details
- 修复了柱形图显示错位
- 移除了骑行页面的活动天数
- 新增了全年骑行总时长、全年骑行总公里数
- 柱形图的宽度不再由骑行时长来计算,而是由骑行公里数来计算显示
- 新增春节快乐红灯笼(移动端不支持)
- 移除
node-sass包,由sass代替
Fix Bugs:柱形图显示错位
当前的柱形图仅为有骑行数据的周生成柱形图,导致柱形图与日历中的周对齐错位,所以即某周没有骑行数据时,柱形图也要生成一根柱子
function generateBarChart() { const barChartElement = document.getElementById('barChart'); // 清空柱形图内容 barChartElement.innerHTML = '';
const today = getChinaTime(); const startDate = getStartDate(today, 21);
// 创建所有周的时间范围 const weeklyData = {}; let currentWeekStart = new Date(startDate); currentWeekStart.setUTCHours(0, 0, 0, 0);
// 按周计算未来 4 周的日期范围 for (let i = 0; i < 4; i++) { const weekStart = new Date(currentWeekStart); const weekEnd = new Date(weekStart); // 一周结束日期为开始日期 +6 天 weekEnd.setUTCDate(weekStart.getUTCDate() + 6); const weekKey = `${weekStart.toISOString().split('T')[0]} - ${weekEnd.toISOString().split('T')[0]}`;
// 初始化每周骑行数据为 0 weeklyData[weekKey] = 0; // 移动到下一周 currentWeekStart.setUTCDate(currentWeekStart.getUTCDate() + 7); }
// 累加每周的骑行距离 processedActivities.forEach(activity => { const activityDate = new Date(activity.activity_time); // 活动所在周的开始日期 const weekStart = getWeekStartDate(activityDate); const weekEnd = new Date(weekStart); weekEnd.setUTCDate(weekStart.getUTCDate() + 6);
const weekKey = `${weekStart.toISOString().split('T')[0]} - ${weekEnd.toISOString().split('T')[0]}`; if (weeklyData[weekKey] !== undefined) { weeklyData[weekKey] += parseFloat(activity.riding_distance); } });
// 获取最大骑行距离(用于柱形图比例) const maxDistance = Math.max(...Object.values(weeklyData), 0);
// 创建并显示每周的柱形图 Object.keys(weeklyData).forEach(week => { // 当前周的骑行距离 const distance = weeklyData[week]; const barContainer = document.createElement('div'); barContainer.className = 'bar-container';
const bar = document.createElement('div'); bar.className = 'bar';
// 计算柱形图的宽度 const width = maxDistance > 0 ? (distance / maxDistance) * 190 : 0; bar.style.setProperty('--bar-width', `${width}px`);
const distanceText = document.createElement('div'); distanceText.className = 'cycling-kilometer'; distanceText.innerText = '0 km';
const messageBox = createMessageBox(); const clickMessageBox = createMessageBox();
barContainer.style.position = 'relative'; bar.appendChild(distanceText); barContainer.appendChild(bar); barContainer.appendChild(messageBox); barContainer.appendChild(clickMessageBox); barChartElement.appendChild(barContainer);
// 动画效果:逐渐显示柱形图宽度 bar.style.width = '0'; bar.offsetHeight; bar.style.transition = 'width 1s ease-out'; bar.style.width = `${width}px`;
distanceText.style.opacity = '1'; // 动态更新柱形图的数值 animateText(distanceText, 0, distance, 1000, true); setupBarInteractions(bar, messageBox, clickMessageBox, distance); });}
// 动态文本显示function animateText(element, startValue, endValue, duration, isDistance = false) { const startTime = performance.now(); function update() { const elapsed = performance.now() - startTime; const progress = Math.min(elapsed / duration, 1); const currentValue = (progress * endValue).toFixed(2); element.innerText = isDistance ? `${currentValue} km` : `${currentValue}h`; if (progress < 1) { requestAnimationFrame(update); } else { element.innerText = isDistance ? `${endValue.toFixed(2)} km` : `${endValue.toFixed(2)}h`; } } update();}New:全年骑行总时长、全年骑行总公里数
// 显示总活动数和总公里数function displayTotalActivities(activities) { // 全年骑行时长 const ridingTimeThisYear = document.getElementById('totalCount'); // 全年骑行公里数 const milesRiddenThisYear = document.getElementById('milesRiddenThisYear'); // 动态年标题《2025 骑行总时长》 const totalTitleElement = document.getElementById('totalTitle');
if (!ridingTimeThisYear || !milesRiddenThisYear || !totalTitleElement) return;
const ridingTimeThisYearValue = ridingTimeThisYear.querySelector('#ridingTimeThisYearValue'); const milesRiddenThisYearValue = milesRiddenThisYear.querySelector('#milesRiddenThisYearValue');
const totalCountSpinner = ridingTimeThisYear.querySelector('.loading-spinner'); const milesRiddenThisYearSpinner = milesRiddenThisYear.querySelector('.loading-spinner');
totalCountSpinner.classList.add('active'); milesRiddenThisYearSpinner.classList.add('active');
const currentYear = new Date().getFullYear(); totalTitleElement.textContent = `${currentYear} 骑行总时长`;
// 筛选全年活动数据 const filteredActivities = activities.filter(activity => { const activityYear = new Date(activity.activity_time).getFullYear(); return activityYear === currentYear; });
// 计算全年活动时间的总和(单位:小时) const totalMovingTime = filteredActivities.reduce((total, activity) => { return total + parseFloat(activity.moving_time) || 0; }, 0);
// 计算全年总公里数 const totalKilometers = calculateTotalKilometers(filteredActivities);
// 动画效果 animateCount(ridingTimeThisYearValue, totalMovingTime, 1000, 50, false); animateCount(milesRiddenThisYearValue, totalKilometers, 1000, 50, true);
setTimeout(() => { console.log(totalKilometers.toFixed(2)); ridingTimeThisYearValue.textContent = `${totalMovingTime.toFixed(2)} h`; milesRiddenThisYearValue.textContent = `${totalKilometers.toFixed(2)} km`; totalCountSpinner.classList.remove('active'); milesRiddenThisYearSpinner.classList.remove('active'); }, 1000);}
// 加载数据并生成日历(async function() { const today = getChinaTime(); const startDate = getStartDate(today, 21);
const activities = await loadActivityData(); // 显示4周的日历 generateCalendar(activities, startDate, 4);
// 显示全年骑行时长和公里数 displayTotalActivities(activities);})();New:春节快乐红灯笼
两年前在冲浪时下载的,已经是第二次用了:
// default.htmlinclude lantern.html
@use 'lantern'Fix Bugs:移除 node-sass 包
node-sass 是基于 LibSass 库构建的,而 LibSass 从 2019 年就停止了更新。所以,Sass 团队放弃了这个项目,重构了 sass(Dart 编写)
sass 相对 node-sass 的优点
原生支持 Dart
sass 是由 Dart 编写,它不再依赖 C++ 编译器,安装和构建速度更快
不再依赖编译
node-sass 需要本地编译,会遇到编译问题,尤其是 Windows 系统上。而 sass 是纯 JavaScript 实现,跨平台时不会有编译问题
{ "devDependencies": { "sass": "^1.83.4", }}