edit | blame | history | raw

/*

This script generates a linear (horizontal) calendar for a specified year, with days flowing left to right and months as rows.

300

Features

  • Horizontal timeline layout with days of the week as columns
  • Month names displayed on both left and right sides
  • Weekend days (Saturday & Sunday) highlighted
  • Day-of-week headers at top and bottom

Customizable Colors

You can personalize the calendar's appearance by defining your own colors:

  1. Create two rectangles in your design.
  2. Select both rectangles before running the script:
    • The fill and stroke colors of the first rectangle will be applied to weekdays.
    • The fill and stroke colors of the second rectangle will be used for weekends.

If no rectangles are selected, the default color schema will be used (white and light blue-gray for weekends).

```javascript
*/

// -------------------------------------
// Constants initiation
// -------------------------------------

const CELL_WIDTH = 176; // Width of each day cell
const CELL_HEIGHT = 288; // Height of each day cell
const START_X = 0; // X start position
const START_Y = 0; // Y start position
const ROW_SPACING = 32; // Space between month rows
const MONTH_LABEL_WIDTH = 240; // Space for month labels on sides

// Colors
let COLOR_WEEKEND = "#e8eaed";
let COLOR_WEEKDAY = "#ffffff";
let COLOR_TEXT = "#000000";
let COLOR_WEEKEND_TEXT = "#000000";
let COLOR_HEADER_TEXT = "#000000";
const COLOR_STROKE = "#d0d4db";
let STROKE_WIDTH = 1;
let FILLSTYLE = "solid";
const ROUGHNESS = 0; // 0 = Architect, 1 = Artist, 2 = Cartoonist
const FONT_FAMILY = 3; // 1 = Virgil, 2 = Helvetica, 3 = Cascadia (code), 4 = Little One

// Font sizes
const FONT_SIZE_DAY = 56;
const FONT_SIZE_HEADER = 48;
const FONT_SIZE_MONTH = 64;
const FONT_SIZE_YEAR = 112;

// Day constants
const SATURDAY = 6;
const SUNDAY = 0;
const JANUARY = 0;
const FIRST_DAY_OF_THE_MONTH = 1;

// Day names (short)
const DAY_NAMES = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];

// Month names (short)
const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

// Number of day columns needed (max 37 to cover all possible month alignments: 6 days offset + 31 days)
const NUM_COLUMNS = 37;

// -------------------------------------

// Ask for requested Year
let requestedYear = parseFloat(new Date().getFullYear());
requestedYear = parseFloat(await utils.inputPrompt("Year?", requestedYear, requestedYear));
if (isNaN(requestedYear)) {
new Notice("Invalid number");
return;
}

// -------------------------------------
// Use selected elements for calendar style
// -------------------------------------

let elements = ea.getViewSelectedElements();
if (elements.length >= 1) {
COLOR_WEEKDAY = elements[0].backgroundColor;
FILLSTYLE = elements[0].fillStyle;
STROKE_WIDTH = elements[0].strokeWidth;
}
if (elements.length >= 2) {
COLOR_WEEKEND = elements[1].backgroundColor;
}

// -------------------------------------
// Helper function to get days in a month
// -------------------------------------

function getDaysInMonth(year, month) {
return new Date(year, month + 1, 0).getDate();
}

// -------------------------------------
// Helper function to get the day of week for first day of month
// -------------------------------------

function getFirstDayOfMonth(year, month) {
return new Date(year, month, 1).getDay();
}

// -------------------------------------
// Draw day-of-week headers
// -------------------------------------

function drawDayHeaders(yPosition) {
ea.style.fontSize = FONT_SIZE_HEADER;
ea.style.strokeColor = COLOR_TEXT;
ea.style.fontFamily = FONT_FAMILY;

for (let col = 0; col < NUM_COLUMNS; col++) {
    const dayIndex = col % 7;
    const x = START_X + MONTH_LABEL_WIDTH + (col * CELL_WIDTH);

    // Center the text in the cell (approximate width of 2 chars)
    const textX = x + (CELL_WIDTH / 2) - (FONT_SIZE_HEADER * 0.6);
    ea.addText(textX, yPosition, DAY_NAMES[dayIndex]);
}

}

// -------------------------------------
// Draw month row
// -------------------------------------

function drawMonthRow(year, month, rowIndex) {
const daysInMonth = getDaysInMonth(year, month);
const firstDayOfWeek = getFirstDayOfMonth(year, month);
const y = START_Y + 160 + (rowIndex * (CELL_HEIGHT + ROW_SPACING));

// Draw month label on the left
ea.style.fontSize = FONT_SIZE_MONTH;
ea.style.strokeColor = COLOR_TEXT;
ea.style.fontFamily = FONT_FAMILY;
const monthLabelY = y + (CELL_HEIGHT / 2) - (FONT_SIZE_MONTH / 2);
ea.addText(START_X, monthLabelY, MONTH_NAMES[month]);

// Draw day cells
for (let day = 1; day <= daysInMonth; day++) {
    const date = new Date(year, month, day);
    const dayOfWeek = date.getDay();
    const col = firstDayOfWeek + day - 1; // Column position based on day of week alignment

    const x = START_X + MONTH_LABEL_WIDTH + (col * CELL_WIDTH);
    const isWeekend = dayOfWeek === SATURDAY || dayOfWeek === SUNDAY;

    // Set cell style
    ea.style.backgroundColor = isWeekend ? COLOR_WEEKEND : COLOR_WEEKDAY;
    ea.style.strokeColor = COLOR_STROKE;
    ea.style.strokeWidth = STROKE_WIDTH;
    ea.style.fillStyle = FILLSTYLE;
    ea.style.roughness = ROUGHNESS;

    // Draw cell rectangle
    ea.addRect(x, y, CELL_WIDTH, CELL_HEIGHT);

    // Draw day number
    ea.style.fontSize = FONT_SIZE_DAY;
    ea.style.strokeColor = COLOR_TEXT;
    ea.style.fontFamily = FONT_FAMILY;

    // Position the day number at top center of the cell
    const dayStr = String(day).padStart(2, "0");
    const charWidth = FONT_SIZE_DAY * 0.6; // Approximate character width
    const textWidth = dayStr.length * charWidth;
    const textX = x + (CELL_WIDTH - textWidth) / 2;
    const textY = y + 32; // 32px padding from top
    ea.addText(textX, textY, dayStr);
}

// Draw month label on the right
ea.style.fontSize = FONT_SIZE_MONTH;
ea.style.strokeColor = COLOR_TEXT;
const rightLabelX = START_X + MONTH_LABEL_WIDTH + (NUM_COLUMNS * CELL_WIDTH) + 60;
ea.addText(rightLabelX, monthLabelY, MONTH_NAMES[month]);

}

// -------------------------------------
// Main calendar generation
// -------------------------------------

// Draw year title (centered above calendar)
ea.style.fontSize = FONT_SIZE_YEAR;
ea.style.strokeColor = COLOR_TEXT;
ea.style.fontFamily = FONT_FAMILY;
const yearX = START_X + MONTH_LABEL_WIDTH + ((NUM_COLUMNS * CELL_WIDTH) / 2) - 120;
ea.addText(yearX, START_Y - 200, String(requestedYear));

// Draw top day-of-week headers
drawDayHeaders(START_Y);

// Draw all 12 months
for (let month = 0; month < 12; month++) {
drawMonthRow(requestedYear, month, month);
}

// Draw bottom day-of-week headers
const bottomHeaderY = START_Y + 160 + (12 * (CELL_HEIGHT + ROW_SPACING)) + 40;
drawDayHeaders(bottomHeaderY);

await ea.addElementsToView(false, false, true);