const util = require('../../utils/util') /** * Generate 4 heat color shades from a primary color. * Returns colors from lightest to darkest. */ const generateHeatColors = (hex) => { if (!hex || hex.charAt(0) !== '#') { return ['#FFE0D0', '#FFB088', '#FF6B35', '#E05520'] } const r = parseInt(hex.slice(1, 3), 16) const g = parseInt(hex.slice(3, 5), 16) const b = parseInt(hex.slice(5, 7), 16) return [ `rgba(${r},${g},${b},0.15)`, // lightest `rgba(${r},${g},${b},0.35)`, // light `rgba(${r},${g},${b},0.65)`, // medium `rgba(${r},${g},${b},0.95)` // darkest ] } const getHeatColor = (duration, colors) => { if (!duration || duration <= 0) return 'transparent' if (duration < 30) return colors[0] if (duration < 60) return colors[1] if (duration < 120) return colors[2] return colors[3] } Component({ properties: { year: { type: Number, value: new Date().getFullYear() }, month: { type: Number, value: new Date().getMonth() + 1 }, records: { type: Array, value: [] }, primaryColor: { type: String, value: '#FF6B35' } }, data: { weeks: [] }, observers: { 'year, month, records, primaryColor'(year, month, records, primaryColor) { this._compute(year, month, records, primaryColor) } }, lifetimes: { ready() { const { year, month, records, primaryColor } = this.properties this._compute(year, month, records, primaryColor) } }, methods: { _compute(year, month, records, primaryColor) { const weeks = util.getMonthCalendar(year, month) const recordMap = {} if (records && records.length) { records.forEach((r) => { const d = parseInt(r.date.split('-')[2]) recordMap[d] = (recordMap[d] || 0) + r.duration }) } const heatColors = generateHeatColors(primaryColor || '#FF6B35') const data = weeks.map((week) => week.map((day) => { if (!day) return null const duration = recordMap[day] || 0 return { day, duration, color: getHeatColor(duration, heatColors) } }) ) this.setData({ weeks: data }) }, onDayTap(e) { const day = e.currentTarget.dataset.day if (!day) return const cell = this.data.weeks.flat().find(c => c && c.day === day) if (!cell || cell.duration <= 0) return this.triggerEvent('daytap', { year: this.properties.year, month: this.properties.month, day, duration: cell.duration }) } } })