ACF Library

drawCalendar

Back to List

Description: A function to draw a calendar image using the Image Drawing capabilities.

FileMaker Prototype:

Set Variable [$res; ACF_Run("drawCalendar"; date_month;  float_width;  float_dpi;  int_displayDays)]

Category: IMAGES

Dependencies

Function source:

Function drawCalendar ( date month, float width, float dpi, int displayDays )

   // ------------------------------------------------------------------
   // Basic date info
   // ------------------------------------------------------------------
   string ys = string (month, "%Y"); 
   string ms = string (month, "%m"); 
   int ims = int(ms); 
   JSON holidays; 
   holidays["a"] = NorwegianHolidaysEN(int(ys)); 
   JSON holidayExtra; 
   int hdaysEx = 0; 
   if (ims == 1) then
      holidayExtra["a"] = NorwegianHolidaysEN(int(ys)-1); 
      hdaysEx = sizeof (holidayExtra["a"]); 
   elseif (ims == 12) then
      holidayExtra["a"] = NorwegianHolidaysEN(int(ys)+1); 
      hdaysEx = sizeof (holidayExtra["a"]); 
   end if

   float fontScale = width / 1024.0; 

   int hdays = sizeof (holidays["a"]); 

   // Normalise displayDays: 5 (Mon–Fri), 6 (Mon–Sat), 7 (Mon–Sun)
   if (displayDays <= 0 || displayDays > 7) then
      displayDays = 7; 
   end if

   // Month and weekday names
   array string mnd = {
      "January", "February", "March", "April", "May", "June",
      "July", "August", "September", "October", "November", "December"
   }; 
   array string sWeekDay = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
   array string WeekDay = {"Monday", "Tuesday", "Wednessday", "Thursday", "Friday", "Saturday"}; 

   // Find first of month
   date dt1th = date( int(ms),1, int(ys)); 
   print format ("\dt1th: %s", string(dt1th)); 
   // ACF %w: 0 = Sunday, 1 = Monday, ... 6 = Saturday
   int dow1th = int (string(dt1th, "%w"));
   if (dow1th == 0) then dow1th = 7; end if   // make Monday=1 ... Sunday=7

   // First Monday shown in the calendar grid
   date calFrom = dt1th - dow1th + 1;   

   // Last day in grid: start with 5 weeks, then trim if the last week is fully next month
   date calTo;
   if (ms == "12") then
      calTo = date(12,31,int(ys)); 
   else
      calTo = date(int(ms)+1, 1, int(ys))-1; 
   end if

   int dowLast = int (string(calTo, "%w"));
   if (dowLast == 0) then dowLast = 7; end if   // make Monday=1 ... Sunday=7

   // Last sunday shown in the calendar grid
   calTo = calTo + (7-dowLast);   

   print format ("\nCalTo(1): %s", string(calTo));
   if (int(string(calTo, "%d")) > 7 && int(string(calTo, "%m"))!=int(ms)) then
      calTo = calTo - 7; 
   end if

   print format ("\nFrom: %s, To:%s, mnt:%s, %s, %s", string(calfrom), string(calTo), string(month, "%d.%m.%Y"), ys, ms); 

   // Number of rows (weeks) in grid
   int calRows = (calTo - calFrom + 1) / 7; 

   // ------------------------------------------------------------------
   // Geometry
   // ------------------------------------------------------------------
   // Margins as 5% of width
   float lm = width * 0.05;
   float rm = lm; 
   float tm = lm; 
   float bm = lm; 

   // Cell width/height (square-ish cells)
   float cellWidth  = (width - lm - rm) / displayDays; 
   float cellHeight = cellWidth*0.8; 
   if (calRows == 6) then
      cellHeight = cellHeight*0.9; 
   end if

   // Header areas
   float hdsize = 36*fontScale; 
   float wdheight = 22*fontScale;
   float monthHeaderHeight   =  hdsize*1.2;  // Month title
   float weekdayHeaderHeight =  wdheight*1.2;  // Weekday row

   float gridTop    = tm + monthHeaderHeight + weekdayHeaderHeight;
   float gridHeight = calRows * cellHeight;
   float height     = gridTop + gridHeight + bm;

   // ------------------------------------------------------------------
   // Create image JSON
   // ------------------------------------------------------------------
   JSON img = NewImage ( width, height, JSON("color", "white", "dpi", dpi) );

   // ------------------------------------------------------------------
   // Fonts
   // ------------------------------------------------------------------
   JSON fontTitle  = JSON("name", "Helvetica", "size", hdsize, "color", "black",
                          "style", JSONarray("bold"));
   JSON fontWeek   = JSON("name", "Helvetica", "size", wdheight, "color", "black",
                          "style", JSONarray("bold"));
   JSON fontDay    = JSON("name", "Helvetica", "size", 18*fontScale, "color", "black");
   JSON fontDayDim = JSON("name", "Helvetica", "size", 18*fontScale, "color", "grey", "alpha", 0.6);
   JSON fontHoliday = JSON("name", "Helvetica", "size", 18*fontScale, "color", "red", "alpha", 1.0);
   // ------------------------------------------------------------------
   // Month title
   // ------------------------------------------------------------------
   ImageSetFont (img, fontTitle);
   string title = format("%s %s", mnd[int(ms)], ys);
   ImageDrawTextBox (
      img,
      lm, tm,
      width - lm - rm, monthHeaderHeight,
      title,
      JSON("align", "center", "valign", "middle")
   );

   // ------------------------------------------------------------------
   // Weekday headers
   // ------------------------------------------------------------------
   ImageSetFont (img, fontWeek);

   int i, j, k;
   float x, y;

   for (i = 1, displayDays)
      x = lm + (i - 1) * cellWidth;
      ImageDrawTextBox (
         img,
         x, tm + monthHeaderHeight,
         cellWidth, weekdayHeaderHeight,
         sWeekDay[i],
         JSON("align", "center", "valign", "middle")
      );
   end for

   // ------------------------------------------------------------------
   // Shading
   // ------------------------------------------------------------------
   x = lm + 5 * cellWidth;
   y = gridTop;
   JSON shading = json("color", "grey", "alpha", 0.1);
   JSON shadingOpts = json("line", "none", "fill", shading);
   if (displayDays == 7) then
      ImageRect(img, x, y, cellWidth*2, cellHeight*calRows, shadingOpts); 
   elseif (displaydays == 6) then
      ImageRect(img, x, y, cellWidth, cellHeight*calRows, shadingOpts); 
   end if
   // ------------------------------------------------------------------
   // Grid lines
   // ------------------------------------------------------------------
   ImageSetLineStyle (img, JSON("color", "black", "width", 1.0*fontScale, "alpha", 0.8));

   // Vertical lines
   for (i = 0, displayDays)
      x = lm + i * cellWidth;
      ImageLine (img, x, gridTop, x, gridTop + gridHeight);
   end for   

   // Horizontal lines
   for (j = 0, calRows)
      y = gridTop + j * cellHeight;
      ImageLine (img, lm, y, lm + displayDays * cellWidth, y);
   end for

   // ------------------------------------------------------------------
   // Fill in the day numbers
   // ------------------------------------------------------------------
   date curDate;
   string curDayStr; 
   int curDay;
   JSON styleDay;
   for (j = 1, calRows) // rows
      for (i = 1, displayDays) // columns

         // Column index (Mon–Sun) is 0..6
         int colIndex = i - 1;

         // Date for this cell: always based on full week (7 days),
         // then we skip actually *displaying* Sat/Sun when displayDays < 7.
         curDate = calFrom + colIndex + (j - 1) * 7;
         curDay  = int(string(curDate, "%d"));

         bool isHoliday = false; 
         string holidayName = ""; 
         for (k = 1 , hdays)
            if ( curDate == date (holidays["a["+k+"].date"],"%Y-%m-%d")) then
               isHoliday = true; 
               holidayName = holidays["a["+k+"].name"]; 
               break;
            end if
         end for
         if (! isHoliday) then
            for (k = 1 , hdaysEx)
               if ( curDate == date (holidayExtra["a["+k+"].date"],"%Y-%m-%d")) then
                  isHoliday = true; 
                  holidayName = holidayExtra["a["+k+"].name"]; 
                  break;
               end if
            end for
         end if

         // Only show the date if the column is within displayDays
         // (for 5 or 6 day weeks, last columns are simply not drawn)
         if (colIndex < displayDays) then
            curDayStr = string(curDay);
            float cellX = lm + colIndex * cellWidth;
            float cellY = gridTop + (j - 1) * cellHeight;

            // Decide style: grey if outside current month
            if (isHoliday) then
               ImageSetFont (img, fontHoliday);
               styleDay = JSON("align", "left", "valign", "top");
               curDayStr += "\n"+holidayName; 
            elseif (int(string(curDate, "%m")) == int(ms)) then
               ImageSetFont (img, fontDay);
               styleDay = JSON("align", "left", "valign", "top");
            else
               ImageSetFont (img, fontDayDim);
               styleDay = JSON("align", "left", "valign", "top");
            end if
            if (i>5) then
               styleDay["color"] = "grey";
               styleDay["alpha"] = 0.0;
            end if

            // Small inset inside the cell
            float insetX = cellWidth * 0.08;
            float insetY = cellHeight * 0.08;

            ImageDrawTextBox (
               img,
               cellX + insetX, cellY + insetY,
               cellWidth - insetX * 2, cellHeight * 0.9,
                curDayStr,
               styleDay
            );
         end if

      end for
   end for

   // ------------------------------------------------------------------
   // Save the final image
   // ------------------------------------------------------------------
   string outPathDir = documents_directory() + "/Calendars";
   // (You might want to ensure directory exists using your filesystem utils.)
   string res = create_directory(outPathDir); 

   string outPath = outPathDir + format("/Calendar-%s-%s-%d.png",
                                        mnd[int(ms)], ys, int(width));

   SaveImage ( img, outPath );
   $$ImgPath = outPath; 
   $$MndName = mnd[int(ms)]; 

   return string (img); 

end

The drawCalendar Function

This function requires at least Plugin version 1.7.8.6

Back to List