问题
GOAL: The goal of this thread is to create two (2) mathematical formulas to replace the long-hand solution by @lawlist in the function lawlist-calendar-cursor-to-visible-date (below).
STORY PROBLEM
There now exists a 12-month calendar in Emacs that scrolls forwards and backwards one month (or more) at a time. The function lawlist-calendar-cursor-to-visible-date is used to mark dates with overlays for designated events (e.g., birthdays, holidays, appointments, etc.); or, to simply move the cursor to a particular date. @lawlist has devised a solution by long-hand, which does not entirely use mathematical equations to calculate the cursor position for each of the 365 days that are displayed. It may be possible to create two (2) concise algorithms to replace the long-hand solution.
A working draft of the 12-month scrolling calendar (without the long-hand solution) may be found here:
https://stackoverflow.com/a/21409154/2112489
LEGEND:
displayed-month (numbers 1 through 12) is the month that appears in the upper left-hand corner of the buffer, and this changes as the 12-month calendar is scrolled forwards or backwards.
The target month (numbers 1 through 12) is the month that we need to locate with assistance from the two mathematical formulas -- its location varies depending upon the date being marked (e.g., birthday, holiday, appointment), and depending upon the displayed-month in the upper left-hand corner of the buffer. The target month can be in any one of 12 possible positions. There are three (3) possible x axis coordinates (i.e., 6, 31, or 56). There are four (4) possible y axis coordinates (i.e., 0, 9, 18 or 27). [Citation to x / y coordinates: http://www.mathsisfun.com/data/cartesian-coordinates.html ]
A row is defined as 3 months horizontally.
A column is defined as 4 months vertically.
The first forumula must equal 0, 9, 18 or 27 depending upon whether the point is on row 1, 2, 3 or 4 -- i.e., from top to bottom.
The second forumula must equal 6, 31, or 56 depending upon whether the point is on column 1, 2 or 3 -- i.e., from left to right.
EXAMPLE:
If
displayed-monthis January (i.e., 1) and the targetmonthis August (i.e., 8), thenrowequals 18 andcolumnequals 31.If
displayed-monthis February (i.e., 2) and the targetmonthis August (i.e., 8), thenrowequals 18 andcolumnequals 6.If
displayed-monthis March (i.e., 3) and the targetmonthis August (i.e., 8), thenrowequals 9 andcolumnequals 56.If
displayed-monthis April (i.e., 4) and targetmonthis August (i.e., 8), thenrowequals 9 andcolumnequals 31.If
displayed-monthis May (i.e., 5) and the targetmonthis August (i.e., 8), thenrowequals 9 andcolumnequals 6.
The 12-month calendar looks like the following as the layout scrolls forward one month at a time:
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
The long-hand solution by @lawlist is as follows:
(defun lawlist-calendar-cursor-to-visible-date (date)
"Move the cursor to DATE that is on the screen."
(let* (
(month (calendar-extract-month date))
(day (calendar-extract-day date))
(year (calendar-extract-year date))
(first-of-month-weekday (calendar-day-of-week (list month 1 year))))
(goto-line
(+ 3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(cond
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
((and
(eq displayed-month 1)
(memq month `(1 2 3)))
0)
((and
(eq displayed-month 1)
(memq month `(4 5 6)))
9)
((and
(eq displayed-month 1)
(memq month `(7 8 9)))
18)
((and
(eq displayed-month 1)
(memq month `(10 11 12)))
27)
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
((and
(eq displayed-month 2)
(memq month `(2 3 4)))
0)
((and
(eq displayed-month 2)
(memq month `(5 6 7)))
9)
((and
(eq displayed-month 2)
(memq month `(8 9 10)))
18)
((and
(eq displayed-month 2)
(memq month `(11 12 1)))
27)
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
((and
(eq displayed-month 3)
(memq month `(3 4 5)))
0)
((and
(eq displayed-month 3)
(memq month `(6 7 8)))
9)
((and
(eq displayed-month 3)
(memq month `(9 10 11)))
18)
((and
(eq displayed-month 3)
(memq month `(12 1 2)))
27)
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
((and
(eq displayed-month 4)
(memq month `(4 5 6)))
0)
((and
(eq displayed-month 4)
(memq month `(7 8 9)))
9)
((and
(eq displayed-month 4)
(memq month `(10 11 12)))
18)
((and
(eq displayed-month 4)
(memq month `(1 2 3)))
27)
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
((and
(eq displayed-month 5)
(memq month `(5 6 7)))
0)
((and
(eq displayed-month 5)
(memq month `(8 9 10)))
9)
((and
(eq displayed-month 5)
(memq month `(11 12 1)))
18)
((and
(eq displayed-month 5)
(memq month `(2 3 4)))
27)
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
((and
(eq displayed-month 6)
(memq month `(6 7 8)))
0)
((and
(eq displayed-month 6)
(memq month `(9 10 11)))
9)
((and
(eq displayed-month 6)
(memq month `(12 1 2)))
18)
((and
(eq displayed-month 6)
(memq month `(3 4 5)))
27)
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
((and
(eq displayed-month 7)
(memq month `(7 8 9)))
0)
((and
(eq displayed-month 7)
(memq month `(10 11 12)))
9)
((and
(eq displayed-month 7)
(memq month `(1 2 3)))
18)
((and
(eq displayed-month 7)
(memq month `(4 5 6)))
27)
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
((and
(eq displayed-month 8)
(memq month `(8 9 10)))
0)
((and
(eq displayed-month 8)
(memq month `(11 12 1)))
9)
((and
(eq displayed-month 8)
(memq month `(2 3 4)))
18)
((and
(eq displayed-month 8)
(memq month `(5 6 7)))
27)
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
((and
(eq displayed-month 9)
(memq month `(9 10 11)))
0)
((and
(eq displayed-month 9)
(memq month `(12 1 2)))
9)
((and
(eq displayed-month 9)
(memq month `(3 4 5)))
18)
((and
(eq displayed-month 9)
(memq month `(6 7 8)))
27)
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
((and
(eq displayed-month 10)
(memq month `(10 11 12)))
0)
((and
(eq displayed-month 10)
(memq month `(1 2 3)))
9)
((and
(eq displayed-month 10)
(memq month `(4 5 6)))
18)
((and
(eq displayed-month 10)
(memq month `(7 8 9)))
27)
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
((and
(eq displayed-month 11)
(memq month `(11 12 1)))
0)
((and
(eq displayed-month 11)
(memq month `(2 3 4)))
9)
((and
(eq displayed-month 11)
(memq month `(5 6 7)))
18)
((and
(eq displayed-month 11)
(memq month `(8 9 10)))
27)
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
((and
(eq displayed-month 12)
(memq month `(12 1 2)))
0)
((and
(eq displayed-month 12)
(memq month `(3 4 5)))
9)
((and
(eq displayed-month 12)
(memq month `(6 7 8)))
18)
((and
(eq displayed-month 12)
(memq month `(9 10 11)))
27) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(/ (+ day -1
(mod
(- (calendar-day-of-week (list month 1 year)) calendar-week-start-day)
7))
7)))
(move-to-column
(+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(cond
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
((and
(eq displayed-month 1)
(memq month `(1 4 7 10)))
6)
((and
(eq displayed-month 1)
(memq month `(2 5 8 11)))
31)
((and
(eq displayed-month 1)
(memq month `(3 6 9 12)))
56)
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
((and
(eq displayed-month 2)
(memq month `(2 5 8 11)))
6)
((and
(eq displayed-month 2)
(memq month `(3 6 9 12)))
31)
((and
(eq displayed-month 2)
(memq month `(4 7 10 1)))
56)
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
((and
(eq displayed-month 3)
(memq month `(3 6 9 12)))
6)
((and
(eq displayed-month 3)
(memq month `(4 7 10 1)))
31)
((and
(eq displayed-month 3)
(memq month `(5 8 11 2)))
56)
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
((and
(eq displayed-month 4)
(memq month `(4 7 10 1)))
6)
((and
(eq displayed-month 4)
(memq month `(5 8 11 2)))
31)
((and
(eq displayed-month 4)
(memq month `(6 9 12 3)))
56)
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
((and
(eq displayed-month 5)
(memq month `(5 8 11 2)))
6)
((and
(eq displayed-month 5)
(memq month `(6 9 12 3)))
31)
((and
(eq displayed-month 5)
(memq month `(7 10 1 4)))
56)
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
((and
(eq displayed-month 6)
(memq month `(6 9 12 3)))
6)
((and
(eq displayed-month 6)
(memq month `(7 10 1 4)))
31)
((and
(eq displayed-month 6)
(memq month `(8 11 2 5)))
56)
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
((and
(eq displayed-month 7)
(memq month `(7 10 1 4)))
6)
((and
(eq displayed-month 7)
(memq month `(8 11 2 5)))
31)
((and
(eq displayed-month 7)
(memq month `(9 12 3 6)))
56)
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
((and
(eq displayed-month 8)
(memq month `(8 11 2 5)))
6)
((and
(eq displayed-month 8)
(memq month `(9 12 3 6)))
31)
((and
(eq displayed-month 8)
(memq month `(10 1 4 7)))
56)
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
((and
(eq displayed-month 9)
(memq month `(9 12 3 6)))
6)
((and
(eq displayed-month 9)
(memq month `(10 1 4 7)))
31)
((and
(eq displayed-month 9)
(memq month `(11 2 5 8)))
56)
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
((and
(eq displayed-month 10)
(memq month `(10 1 4 7)))
6)
((and
(eq displayed-month 10)
(memq month `(11 2 5 8)))
31)
((and
(eq displayed-month 10)
(memq month `(12 3 6 9)))
56)
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
((and
(eq displayed-month 11)
(memq month `(11 2 5 8)))
6)
((and
(eq displayed-month 11)
(memq month `(12 3 6 9)))
31)
((and
(eq displayed-month 11)
(memq month `(1 4 7 10)))
56)
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
((and
(eq displayed-month 12)
(memq month `(12 3 6 9)))
6)
((and
(eq displayed-month 12)
(memq month `(1 4 7 10)))
31)
((and
(eq displayed-month 12)
(memq month `(2 5 8 11)))
56) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(* 3 (mod
(- (calendar-day-of-week date) calendar-week-start-day)
7))))))
回答1:
I must be missing something because it looks like the formulas are as simple as (pseudocode):
first = 9 * ( rows - 1 )
second = 6 + 25 * ( cols - 1 )
based on your edit, you can calculate the rows and cols to move with:
if target > display
difference = target - display
else
difference = 12 + target - display
rows = difference / 3
cols = difference % 3
rowmove = 9 * rows
colmove = 6 + 25 * cols
And then use the formula above.
My attempt at elisp:
(let difference (if (>= target-month display-month)
(- target-month display-month)
(- (+ target-month 12) display-month)))
(let rows (/ difference 3))
(let cols (% difference 3))
(let rowmove (* 9 rows))
(let colmove (+ 6 (* 25 cols)))
来源:https://stackoverflow.com/questions/21642010/algorithms-for-moving-the-cursor-to-a-date-on-a-12-month-rotating-calendar-in-em