diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index b109eb2b223..f091e319f44 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,5 +1,3 @@ -/* eslint-disable no-var, vars-on-top, one-var, one-var-declaration-per-line, max-len, class-methods-use-this */ - import d3 from 'd3'; const LOADING_HTML = ` @@ -8,8 +6,22 @@ const LOADING_HTML = ` `; +function formatTooltipText({ date, count }) { + const dateObject = new Date(date); + const dateDayName = gl.utils.getDayName(dateObject); + const dateText = dateObject.format('mmm d, yyyy'); + + let contribText = 'No contributions'; + if (count > 0) { + contribText = `${count} contribution${count > 1 ? 's' : ''}`; + } + return `${contribText}
${dateDayName} ${dateText}`; +} + +const initColorKey = () => d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]); + export default class ActivityCalendar { - constructor(timestamps, calendarActivitiesPath) { + constructor(container, timestamps, calendarActivitiesPath) { this.calendarActivitiesPath = calendarActivitiesPath; this.clickDay = this.clickDay.bind(this); this.currentSelectedDate = ''; @@ -22,22 +34,22 @@ export default class ActivityCalendar { // Loop through the timestamps to create a group of objects // The group of objects will be grouped based on the day of the week they are this.timestampsTmp = []; - var group = 0; + let group = 0; - var today = new Date(); + const today = new Date(); today.setHours(0, 0, 0, 0, 0); - var oneYearAgo = new Date(today); + const oneYearAgo = new Date(today); oneYearAgo.setFullYear(today.getFullYear() - 1); - var days = gl.utils.getDayDifference(oneYearAgo, today); + const days = gl.utils.getDayDifference(oneYearAgo, today); - for (var i = 0; i <= days; i += 1) { - var date = new Date(oneYearAgo); + for (let i = 0; i <= days; i += 1) { + const date = new Date(oneYearAgo); date.setDate(date.getDate() + i); - var day = date.getDay(); - var count = timestamps[date.format('yyyy-mm-dd')] || 0; + const day = date.getDay(); + const count = timestamps[date.format('yyyy-mm-dd')] || 0; // Create a new group array if this is the first day of the week // or if is first object @@ -47,28 +59,30 @@ export default class ActivityCalendar { } // Push to the inner array the values that will be used to render map - var innerArray = this.timestampsTmp[group - 1]; + const innerArray = this.timestampsTmp[group - 1]; innerArray.push({ count, date, day }); } // Init color functions - this.colorKey = this.initColorKey(); + this.colorKey = initColorKey(); this.color = this.initColor(); // Init the svg element - this.renderSvg(group); + this.svg = this.renderSvg(container, group); this.renderDays(); this.renderMonths(); this.renderDayTitles(); this.renderKey(); - this.initTooltips(); + + // Init tooltips + $(`${container} .js-tooltip`).tooltip({ html: true }); } // Add extra padding for the last month label if it is also the last column getExtraWidthPadding(group) { - var extraWidthPadding = 0; - var lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth(); - var secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth(); + let extraWidthPadding = 0; + const lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth(); + const secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth(); if (lastColMonth !== secondLastColMonth) { extraWidthPadding = 3; @@ -77,9 +91,9 @@ export default class ActivityCalendar { return extraWidthPadding; } - renderSvg(group) { - var width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group); - this.svg = d3.select('.js-contrib-calendar') + renderSvg(container, group) { + const width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group); + return d3.select(container) .append('svg') .attr('width', width) .attr('height', 167) @@ -90,15 +104,14 @@ export default class ActivityCalendar { this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g') .attr('transform', (group, i) => { _.each(group, (stamp, a) => { - var lastMonth, lastMonthX, month, x; if (a === 0 && stamp.day === 0) { - month = stamp.date.getMonth(); - x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace; - lastMonth = _.last(this.months); - if (lastMonth != null) { - lastMonthX = lastMonth.x; - } - if (lastMonth == null || (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonthX)) { + const month = stamp.date.getMonth(); + const x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace; + const lastMonth = _.last(this.months); + if ( + lastMonth == null || + (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonth.x) + ) { this.months.push({ month, x }); } } @@ -106,29 +119,20 @@ export default class ActivityCalendar { return `translate(${(this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace}, 18)`; }) .selectAll('rect') - .data(stamp => stamp) - .enter() - .append('rect') - .attr('x', '0') - .attr('y', stamp => this.daySizeWithSpace * stamp.day) - .attr('width', this.daySize) - .attr('height', this.daySize) - .attr('title', (stamp) => { - var contribText, date, dateText; - date = new Date(stamp.date); - contribText = 'No contributions'; - if (stamp.count > 0) { - contribText = `${stamp.count} contribution${stamp.count > 1 ? 's' : ''}`; - } - dateText = date.format('mmm d, yyyy'); - return `${contribText}
${gl.utils.getDayName(date)} ${dateText}`; - }) - .attr('class', 'user-contrib-cell js-tooltip') - .attr('fill', stamp => ( - stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed' - )) - .attr('data-container', 'body') - .on('click', this.clickDay); + .data(stamp => stamp) + .enter() + .append('rect') + .attr('x', '0') + .attr('y', stamp => this.daySizeWithSpace * stamp.day) + .attr('width', this.daySize) + .attr('height', this.daySize) + .attr('fill', stamp => ( + stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed' + )) + .attr('title', stamp => formatTooltipText(stamp)) + .attr('class', 'user-contrib-cell js-tooltip') + .attr('data-container', 'body') + .on('click', this.clickDay); } renderDayTitles() { @@ -190,15 +194,10 @@ export default class ActivityCalendar { } initColor() { - var colorRange; - colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; + const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; return d3.scale.threshold().domain([0, 10, 20, 30]).range(colorRange); } - initColorKey() { - return d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]); - } - clickDay(stamp) { if (this.currentSelectedDate !== stamp.date) { this.currentSelectedDate = stamp.date; @@ -222,8 +221,4 @@ export default class ActivityCalendar { $('.user-calendar-activities').html(''); } } - - initTooltips() { - $('.js-contrib-calendar .js-tooltip').tooltip({ html: true }); - } } diff --git a/app/assets/javascripts/users/user_tabs.js b/app/assets/javascripts/users/user_tabs.js index fd9fe597303..5fe6603ce7b 100644 --- a/app/assets/javascripts/users/user_tabs.js +++ b/app/assets/javascripts/users/user_tabs.js @@ -158,7 +158,7 @@ export default class UserTabs { $calendarWrap.html(CALENDAR_TEMPLATE); // eslint-disable-next-line no-new - new ActivityCalendar(activityData, calendarActivitiesPath); + new ActivityCalendar('.js-contrib-calendar', activityData, calendarActivitiesPath); }, });