diff --git a/bower.json b/bower.json index 7f35c43..1380948 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-calendar-heatmap", - "version": "0.2.4", + "version": "0.2.5", "main": [ "dist/calendar-heatmap.min.js", "dist/calendar-heatmap.min.css" diff --git a/dist/calendar-heatmap.min.js b/dist/calendar-heatmap.min.js index d1406d3..6b38a49 100644 --- a/dist/calendar-heatmap.min.js +++ b/dist/calendar-heatmap.min.js @@ -1 +1 @@ -"use strict";angular.module("g1b.calendar-heatmap",[]).directive("calendarHeatmap",["$window",function(t){return{restrict:"E",scope:{data:"=",color:"=?",overview:"=?",handler:"=?"},replace:!0,template:'
',link:function(e,n){var a=5,r=1,o=1e3,i=200,l=10,c=40,s=20,d=500,u=!1,m=250,f=15;e.overview=e.overview||"year",e.history=["year"],e.selected={};var v=d3.select(n[0]).append("svg").attr("class","svg"),h=v.append("g"),y=v.append("g"),p=v.append("g"),w=d3.select(n[0]).append("div").attr("class","heatmap-tooltip").style("opacity",0),k=function(){var t=864e5,e=(moment()-moment().subtract(1,"year").subtract(1,"day"))/t-364,n=Math.ceil((moment()-moment().startOf("week"))/t),a=n0?r(t.total):"transparent"}).on("click",function(t){u||0!==t.total&&(u=!0,e.selected=t,e.hideTooltip(),e.removeYearOverview(),e.overview="day",e.drawChart())}).on("mouseover",function(t){if(!u){var n=d3.select(this);!function c(){n=n.transition().duration(d).ease("ease-in").attr("x",function(t){return s(t)-(1.1*l-l)/2}).attr("y",function(t){return v(t)-(1.1*l-l)/2}).attr("width",1.1*l).attr("height",1.1*l).transition().duration(d).ease("ease-in").attr("x",function(t){return s(t)+(l-p(t))/2}).attr("y",function(t){return v(t)+(l-p(t))/2}).attr("width",function(t){return p(t)}).attr("height",function(t){return p(t)}).each("end",c)}();var a="";a+='
'+(t.total?e.formatTime(t.total):"No time")+" tracked
",a+="
on "+moment(t.date).format("dddd, MMM Do YYYY")+"

",angular.forEach(t.summary,function(t){a+="
"+t.name+"",a+=""+e.formatTime(t.value)+"
"});var r=s(t)+l;o-r
",a+="
"+(t.value?e.formatTime(t.value):"No time")+" tracked
",a+="
on "+moment(n).format("dddd, MMM Do YYYY")+"
";for(var r=g(moment(n).week())+f;o-r
",a+="
"+(t.value?e.formatTime(t.value):"No time")+" tracked
",a+="
on "+moment(n).format("dddd, MMM Do YYYY")+"
";var r=parseInt(d3.select(this.parentNode).attr("total"));M.domain([0,r]);for(var i=parseInt(d3.select(this).attr("x"))+M(t.value)/4+m/4;o-i

",a+="
"+(t.value?e.formatTime(t.value):"No time")+" tracked
",a+="
on "+moment(t.date).format("dddd, MMM Do YYYY HH:mm")+"
";for(var i=100*t.value/86400+r(moment(t.date));o-i=n&&e<=a?1:.1})}}).on("mouseout",function(){u||h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",.5)}),y.selectAll(".label-project").remove(),y.selectAll(".label-project").data(t).enter().append("text").attr("class","label label-project").attr("x",a).attr("y",function(t){return n(t)+n.rangeBand()/2}).attr("min-height",function(){return n.rangeBand()}).style("text-anchor","left").attr("font-size",function(){return Math.floor(c/3)+"px"}).text(function(t){return t}).each(function(){for(var t=d3.select(this),e=t.node().getComputedTextLength(),n=t.text();e>1.5*c&&n.length>0;)n=n.slice(0,-1),t.text(n+"..."),e=t.node().getComputedTextLength()}).on("mouseenter",function(t){u||h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",function(e){return e.name===t?1:.1})}).on("mouseout",function(){u||h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",.5)}),e.drawButton()},e.drawButton=function(){p.selectAll(".button").remove();var t=p.append("g").attr("class","button button-back").style("opacity",0).on("click",function(){u||(u=!0,"month"===e.overview?e.removeMonthOverview():"week"===e.overview?e.removeWeekOverview():"day"===e.overview&&e.removeDayOverview(),e.history.pop(),e.overview=e.history.pop(),e.drawChart())});t.append("circle").attr("cx",c/2.25).attr("cy",c/2.5).attr("r",l/2),t.append("text").attr("x",c/2.25).attr("y",c/2.75).attr("dy",function(){return Math.floor(o/100)/2.5}).attr("font-size",function(){return Math.floor(c/3)+"px"}).html("←"),t.transition().duration(d).ease("ease-in").style("opacity",1)},e.removeYearOverview=function(){h.selectAll(".item-circle").transition().duration(d).ease("ease").style("opacity",0).remove(),y.selectAll(".label-day").remove(),y.selectAll(".label-month").remove()},e.removeMonthOverview=function(){h.selectAll(".item-block-month").selectAll(".item-block-rect").transition().duration(d).ease("ease-in").style("opacity",0).attr("x",function(t,e){return e%2===0?-o/3:o/3}).remove(),y.selectAll(".label-day").remove(),y.selectAll(".label-week").remove(),e.hideBackButton()},e.removeWeekOverview=function(){h.selectAll(".item-block-week").selectAll(".item-block-rect").transition().duration(d).ease("ease-in").style("opacity",0).attr("x",function(t,e){return e%2===0?-o/3:o/3}).remove(),y.selectAll(".label-day").remove(),y.selectAll(".label-week").remove(),e.hideBackButton()},e.removeDayOverview=function(){h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",0).attr("x",function(t,e){return e%2===0?-o/3:o/3}).remove(),y.selectAll(".label-time").remove(),y.selectAll(".label-project").remove(),e.hideBackButton()},e.hideTooltip=function(){w.transition().duration(d/2).ease("ease-in").style("opacity",0)},e.hideBackButton=function(){p.selectAll(".button").transition().duration(d).ease("ease").style("opacity",0).remove()},e.formatTime=function(t){var e=parseInt(t,10),n=Math.floor(e/3600),a=Math.floor((e-3600*n)/60),r="";return n>0&&(r+=1===n?"1 hour ":n+" hours "),a>0&&(r+=1===a?"1 minute":a+" minutes"),0===n&&0===a&&(r=t+" seconds"),r}}}}]); \ No newline at end of file +"use strict";angular.module("g1b.calendar-heatmap",[]).directive("calendarHeatmap",["$window",function(t){return{restrict:"E",scope:{data:"=",color:"=?",overview:"=?",handler:"=?"},replace:!0,template:'
',link:function(e,n){var a=5,r=1,o=1e3,i=200,l=10,c=40,s=20,d=500,u=!1,m=250,f=15;e.overview=e.overview||"year",e.history=["year"],e.selected={};var v=d3.select(n[0]).append("svg").attr("class","svg"),h=v.append("g"),y=v.append("g"),p=v.append("g"),w=d3.select(n[0]).append("div").attr("class","heatmap-tooltip").style("opacity",0),k=function(){var t=Math.floor((moment()-moment().subtract(1,"year").startOf("week"))/864e5),e=Math.trunc(t/7),n=e+1;return n};e.$watch(function(){return n[0].clientWidth},function(t){t&&(o=t<1e3?1e3:t,l=(o-c)/k()-a,i=c+7*(l+a),v.attr({width:o,height:i}),e.data&&e.data[0].summary&&e.drawChart())}),angular.element(t).bind("resize",function(){e.$apply()}),e.$watch("data",function(t){t&&(t[0].summary||t.map(function(t){var e=t.details.reduce(function(t,e){return t[e.name]?t[e.name].value+=e.value:t[e.name]={value:e.value},t},{}),n=Object.keys(e).map(function(t){return{name:t,value:e[t].value}});return t.summary=n.sort(function(t,e){return e.value-t.value}),t}),e.drawChart())}),e.drawChart=function(){e.data&&("year"===e.overview?e.drawYearOverview():"month"===e.overview?e.drawMonthOverview():"week"===e.overview?e.drawWeekOverview():"day"===e.overview&&e.drawDayOverview())},e.drawYearOverview=function(){e.history[e.history.length-1]!==e.overview&&e.history.push(e.overview);var t=moment().startOf("day").subtract(1,"year"),n=d3.max(e.data,function(t){return t.total}),r=d3.scale.linear().range(["#ffffff",e.color||"#ff4500"]).domain([-.15*n,n]),s=function(e){var n=moment(e.date),r=Math.floor((n-moment(t).startOf("week"))/864e5),o=Math.trunc(r/7);return o*(l+a)+c},v=function(t){return c+moment(t.date).weekday()*(l+a)},p=function(t){return n<=0?l:.75*l+l*t.total/n*.25};h.selectAll(".item-circle").remove(),h.selectAll(".item-circle").data(e.data).enter().append("rect").attr("class","item item-circle").style("opacity",0).attr("x",function(t){return s(t)+(l-p(t))/2}).attr("y",function(t){return v(t)+(l-p(t))/2}).attr("rx",function(t){return p(t)}).attr("ry",function(t){return p(t)}).attr("width",function(t){return p(t)}).attr("height",function(t){return p(t)}).attr("fill",function(t){return t.total>0?r(t.total):"transparent"}).on("click",function(t){u||0!==t.total&&(u=!0,e.selected=t,e.hideTooltip(),e.removeYearOverview(),e.overview="day",e.drawChart())}).on("mouseover",function(t){if(!u){var n=d3.select(this);!function c(){n=n.transition().duration(d).ease("ease-in").attr("x",function(t){return s(t)-(1.1*l-l)/2}).attr("y",function(t){return v(t)-(1.1*l-l)/2}).attr("width",1.1*l).attr("height",1.1*l).transition().duration(d).ease("ease-in").attr("x",function(t){return s(t)+(l-p(t))/2}).attr("y",function(t){return v(t)+(l-p(t))/2}).attr("width",function(t){return p(t)}).attr("height",function(t){return p(t)}).each("end",c)}();var a="";a+='
'+(t.total?e.formatTime(t.total):"No time")+" tracked
",a+="
on "+moment(t.date).format("dddd, MMM Do YYYY")+"

",angular.forEach(t.summary,function(t){a+="
"+t.name+"",a+=""+e.formatTime(t.value)+"
"});var r=s(t)+l;o-r

",a+="
"+(t.value?e.formatTime(t.value):"No time")+" tracked
",a+="
on "+moment(n).format("dddd, MMM Do YYYY")+"
";for(var r=b(moment(n).week())+f;o-r
",a+="
"+(t.value?e.formatTime(t.value):"No time")+" tracked
",a+="
on "+moment(n).format("dddd, MMM Do YYYY")+"
";var r=parseInt(d3.select(this.parentNode).attr("total"));M.domain([0,r]);for(var i=parseInt(d3.select(this).attr("x"))+M(t.value)/4+m/4;o-i

",a+="
"+(t.value?e.formatTime(t.value):"No time")+" tracked
",a+="
on "+moment(t.date).format("dddd, MMM Do YYYY HH:mm")+"
";for(var i=100*t.value/86400+r(moment(t.date));o-i=n&&e<=a?1:.1})}}).on("mouseout",function(){u||h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",.5)}),y.selectAll(".label-project").remove(),y.selectAll(".label-project").data(t).enter().append("text").attr("class","label label-project").attr("x",a).attr("y",function(t){return n(t)+n.rangeBand()/2}).attr("min-height",function(){return n.rangeBand()}).style("text-anchor","left").attr("font-size",function(){return Math.floor(c/3)+"px"}).text(function(t){return t}).each(function(){for(var t=d3.select(this),e=t.node().getComputedTextLength(),n=t.text();e>1.5*c&&n.length>0;)n=n.slice(0,-1),t.text(n+"..."),e=t.node().getComputedTextLength()}).on("mouseenter",function(t){u||h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",function(e){return e.name===t?1:.1})}).on("mouseout",function(){u||h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",.5)}),e.drawButton()},e.drawButton=function(){p.selectAll(".button").remove();var t=p.append("g").attr("class","button button-back").style("opacity",0).on("click",function(){u||(u=!0,"month"===e.overview?e.removeMonthOverview():"week"===e.overview?e.removeWeekOverview():"day"===e.overview&&e.removeDayOverview(),e.history.pop(),e.overview=e.history.pop(),e.drawChart())});t.append("circle").attr("cx",c/2.25).attr("cy",c/2.5).attr("r",l/2),t.append("text").attr("x",c/2.25).attr("y",c/2.75).attr("dy",function(){return Math.floor(o/100)/2.5}).attr("font-size",function(){return Math.floor(c/3)+"px"}).html("←"),t.transition().duration(d).ease("ease-in").style("opacity",1)},e.removeYearOverview=function(){h.selectAll(".item-circle").transition().duration(d).ease("ease").style("opacity",0).remove(),y.selectAll(".label-day").remove(),y.selectAll(".label-month").remove()},e.removeMonthOverview=function(){h.selectAll(".item-block-month").selectAll(".item-block-rect").transition().duration(d).ease("ease-in").style("opacity",0).attr("x",function(t,e){return e%2===0?-o/3:o/3}).remove(),y.selectAll(".label-day").remove(),y.selectAll(".label-week").remove(),e.hideBackButton()},e.removeWeekOverview=function(){h.selectAll(".item-block-week").selectAll(".item-block-rect").transition().duration(d).ease("ease-in").style("opacity",0).attr("x",function(t,e){return e%2===0?-o/3:o/3}).remove(),y.selectAll(".label-day").remove(),y.selectAll(".label-week").remove(),e.hideBackButton()},e.removeDayOverview=function(){h.selectAll(".item-block").transition().duration(d).ease("ease-in").style("opacity",0).attr("x",function(t,e){return e%2===0?-o/3:o/3}).remove(),y.selectAll(".label-time").remove(),y.selectAll(".label-project").remove(),e.hideBackButton()},e.hideTooltip=function(){w.transition().duration(d/2).ease("ease-in").style("opacity",0)},e.hideBackButton=function(){p.selectAll(".button").transition().duration(d).ease("ease").style("opacity",0).remove()},e.formatTime=function(t){var e=parseInt(t,10),n=Math.floor(e/3600),a=Math.floor((e-3600*n)/60),r="";return n>0&&(r+=1===n?"1 hour ":n+" hours "),a>0&&(r+=1===a?"1 minute":a+" minutes"),0===n&&0===a&&(r=t+" seconds"),r}}}}]); \ No newline at end of file diff --git a/package.json b/package.json index 512d54c..7f8bbcc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-calendar-heatmap", - "version": "0.2.4", + "version": "0.2.5", "description": "Angular directive of calendar heatmap graph representing time series data.", "homepage": "https://github.com/g1eb/calendar-heatmap#readme", "repository": { diff --git a/src/calendar-heatmap.js b/src/calendar-heatmap.js index 82bfab8..73f5839 100644 --- a/src/calendar-heatmap.js +++ b/src/calendar-heatmap.js @@ -53,10 +53,9 @@ angular.module('g1b.calendar-heatmap', []). .style('opacity', 0); var getNumberOfWeeks = function () { - var dayInMillis = 1000*60*60*24; - var extraDays = ((moment() - moment().subtract(1, 'year').subtract(1, 'day')) / dayInMillis) - 52 * 7; - var currentDay = Math.ceil((moment() - moment().startOf('week')) / dayInMillis); - var numWeeks = currentDay < extraDays ? 54 : 53; + var dayIndex = Math.floor((moment() - moment().subtract(1, 'year').startOf('week')) / 86400000); + var colIndex = Math.trunc(dayIndex / 7); + var numWeeks = colIndex + 1; return numWeeks; } @@ -149,8 +148,9 @@ angular.module('g1b.calendar-heatmap', []). var calcItemX = function (d) { var date = moment(d.date); - var week_num = date.week() - year_ago.week() + (year_ago.weeksInYear() * (date.weekYear() - year_ago.weekYear())); - return week_num * (item_size + gutter) + label_padding; + var dayIndex = Math.floor((date - moment(year_ago).startOf('week')) / 86400000); + var colIndex = Math.trunc(dayIndex / 7); + return colIndex * (item_size + gutter) + label_padding; }; var calcItemY = function (d) { return label_padding + moment(d.date).weekday() * (item_size + gutter);