(function ($) {
$.fn.calendar_yearview_blocks = function (options) {
// Format string
if (!String.prototype.formatString) {
String.prototype.formatString = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] !== 'undefined'
? args[number]
: match
;
});
};
}
// If the number less than 10, add a zero before it
var prettyNumber = function (number) {
return number < 10 ? '0' + number.toString() : number = number.toString();
};
var getDisplayDate = function (date_obj) {
var pretty_month = prettyNumber(date_obj.getMonth() + 1);
var pretty_date = prettyNumber(date_obj.getDate());
return "{0}-{1}-{2}".formatString(date_obj.getFullYear(), pretty_month, pretty_date);
};
var start = function () {
obj_timestamp = JSON.parse(settings.data);
var wrap_chart = _this;
var end_date = new Date(settings.final_date);
var current_date = new Date();
var start_date = new Date();
start_date.setMonth(end_date.getMonth() - 12);
var start_weekday = settings.start_monday === true?1:0;
for (var i = 0; i < 7; i++) {
var day = start_date.getDay();
if (day === start_weekday) {
break;
}
else {
// Loop until start_weekday
start_date.setDate(start_date.getDate() + 1);
}
}
var loop_html = "";
// One year has 52 weeks
var step = 13; // Amount of pixels to move
var month_position = [];
month_position.push({month_index: start_date.getMonth(), x: 0});
var using_month = start_date.getMonth();
for (var i = 0; i <= 52; i++) { // For each week, generate a column
var g_x = i * step;
var item_html = '';
for (var j = 0; j < 7; j++) { // For each weekday, generate a row
if (start_date > end_date) {
// Break the loop when today's date is found
break;
}
var y = j * step;
var month_in_day = start_date.getMonth();
var data_date = getDisplayDate(start_date);
// Check first day in week
if (j === start_weekday && month_in_day !== using_month) {
using_month = month_in_day;
month_position.push({month_index: using_month, x: g_x});
}
// Put a box around today's date
if (settings.stylize_today) {
var match_today = current_date.getTime() === start_date.getTime() ? '" style="stroke:black;stroke-width:2;opacity:0.5"' : '';
} else {
var match_today = "";
}
var items = [];
var legend = '', items_str = '';
if (obj_timestamp[data_date]) {
if (obj_timestamp[data_date].items) {
items = obj_timestamp[data_date].items;
items_str = items.join(", ")
items_str = items_str.replaceAll('&', '&');
items_str = items_str.replaceAll('"', '"');
}
if (obj_timestamp[data_date].legend) {
legend = obj_timestamp[data_date].legend;
legend = legend.replaceAll('&', '&');
legend = legend.replaceAll('"', '"');
}
}
var item_name = items[0]?items[0]:false;
var color = settings.colors[item_name]?settings.colors[item_name]:settings.colors['default'];
// Fill a square for the 1st item
item_html += '';
if (items.length === 2) { // Fill a trangle for the 2nd
var item_name_1 = items[1]?items[1]:false;
var color_1 = settings.colors[item_name_1]?settings.colors[item_name_1]:settings.colors['default'];
item_html += '';
} else if (items.length === 3) { // Fill 2 rectangles for 2nd and 3rd
var item_name_1 = items[1]?items[1]:false;
var color_1 = settings.colors[item_name_1]?settings.colors[item_name_1]:settings.colors['default'];
var item_name_2 = items[2]?items[2]:false;
var color_2 = settings.colors[item_name_2]?settings.colors[item_name_2]:settings.colors['default'];
item_html += '';
item_html += '';
} else if (items.length === 4) { // Fill 3 cubes for 2nd, 3rd and 4th
var item_name_1 = items[1]?items[1]:false;
var color_1 = settings.colors[item_name_1]?settings.colors[item_name_1]:settings.colors['default'];
var item_name_2 = items[2]?items[2]:false;
var color_2 = settings.colors[item_name_2]?settings.colors[item_name_2]:settings.colors['default'];
var item_name_3 = items[3]?items[3]:false;
var color_3 = settings.colors[item_name_3]?settings.colors[item_name_3]:settings.colors['default'];
item_html += '';
item_html += '';
item_html += '';
}
// Move on to the next day
start_date.setDate(start_date.getDate() + 1);
}
item_html += "";
loop_html += item_html;
}
// Trick
if (month_position[1].x - month_position[0].x < 40) {
// Fix ugly graph by removing the first item
month_position.shift(0);
}
// Add labels for Months
for (var i = 0; i < month_position.length; i++) {
var item = month_position[i];
var month_name = settings.month_names[item.month_index];
loop_html += '' + month_name + '';
}
// Add labels for Weekdays
if (settings.start_monday === true) {
loop_html += '{0}'.formatString(settings.day_names[0]) +
'{0}'.formatString(settings.day_names[1]) +
'{0}'.formatString(settings.day_names[2]) +
'{0}'.formatString(settings.day_names[3]);
} else {
loop_html += '{0}'.formatString(settings.day_names[0]) +
'{0}'.formatString(settings.day_names[1]) +
'{0}'.formatString(settings.day_names[2]);
}
// Fixed size with width= 721 and height = 110
var wire_html =
'';
wrap_chart.html(wire_html);
_this.find('rect, polygon').on("mouseenter", mouseEnter);
_this.find('rect, polygon').on("mouseleave", mouseLeave);
_this.find('rect, polygon').on("click", mouseClick);
appendTooltip();
};
var mouseLeave = function (evt) {
$('.svg-tip').hide();
};
var mouseClick = function (evt) {
var items = $(evt.target).attr('data-items');
var date = $(evt.target).attr('data-date');
$("#moreinfo").text("On {0}, following items are seen: {1}".formatString(date, items))
};
// Handle mouseEnter event when entering into rect element
var mouseEnter = function (evt) {
var target_offset = $(evt.target).offset();
var items = $(evt.target).attr('data-items');
var legend = $(evt.target).attr('data-legend');
var date = $(evt.target).attr('data-date');
var text = settings.tooltip_style === 'default' ? "{0}: {1}".formatString(date, legend ? legend : items) : (legend ? legend : items);
// Depending on settings, only show a tooltip when there's something to be shown
if (items.length >= 1 || settings.always_show_tooltip === true) {
var svg_tip = $('.svg-tip').show();
svg_tip.html(text);
var svg_width = Math.round(svg_tip.width() / 2 + 5);
var svg_height = svg_tip.height() * 2 + 10;
svg_tip.css({top: target_offset.top - svg_height - 5});
svg_tip.css({left: target_offset.left - svg_width});
}
};
// Append tooltip to display when the mouse enters the rect element
// Default is display:none
var appendTooltip = function () {
if ($('.svg-tip').length === 0) {
$('body').append('
');
}
};
// Default settings which can be overridden by the user
var settings = $.extend({
colors: {
'default': '#eeeeee'
},
month_names: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
day_names: ['M', 'W', 'F', 'S'],
start_monday: true,
always_show_tooltip: false,
stylize_today: false,
final_date: new Date().toISOString().slice(0, 10),
tooltip_style: 'default', // or 'custom'
data: []
}, options);
var _this = $(this);
start();
};
}(jQuery));