Круглендарь на 2014 год



    Здравствуйте, друзья!
    В прошлом году я сделал первый круглендарь.
    Продолжаем, экспериментируем.

    Идея проекта — создать календарь, позволяющий увидеть все дни года, вспомнить приятные моменты прошлого и ожидаемые события будущего.
    Есть куча аналогов, особенностью этого проета является минималистичность и пустота, ведь на первом плане должны быть каракули обладателя.

    Скачиваем с Github (или git clone github.com/illus0r/kruglendar2014.git)
    • Распечатываем на формате А1
    • Вешаем на стенку в удобном месте (особенно хорошо — в туалете), рядом — фломастер на ниточке.
    • Случилось что-то интересное? Лихо дорисовываем круглендарь! К концу года будет любо-дорого смотреть.

    Лицензия Creative Commons
    Также, как и предыдущий, этот календарь публикуется под лицензией Creative Commons «Attribution» («Атрибуция») 3.0 Непортированной.

    С Новым Годом!

    Под катом немного о процессе создания.

    Процесс


    В этом году всё началось с набросков. Думал сделать что-то навороченное и фрактальное, с лунным календарём в довесок. Но вернулся к первому минималистичному эскизу.



    Как заправский лентяй, я решил написать скрипт, который выполнить львиную долю работы. Так появилась возможность поиграть размерами, толщинами и, конечно же, шрифтами.

    Сперва задавал радиусы и толщины окружностей вручную, но потом решил, что будет гораздо естественнее и приятнее, если они определяться геометрической прогрессией.

    Над цветами долго не думал. В фотошопе, открыл окошко выбора цвета и переключился в режим с одинаковой Lightness цветовой схемы Lab (она учитывает восприятие цвета человеком и интенсивность цветов будет схожей).



    Несколько точек есть, остальные получаем путём интерполяции. Хорошо, я выбрал не самый простой путь, и можно было обойтись маской в иллюстраторе. Но ведь так веселее!

    Самоё скрипт
    # -*- coding: utf-8 -*-
    import svgwrite, math, numpy
    
    def frange(x, y, jump):
      while x < y:
        yield x
        x += jump
    
    if __name__ == '__main__':
      # Calendar parameters
      textAngleShift = -(0.26*math.pi*2/365)
      canvasSize = (500,707)
      mid = canvasSize[0]/2.0, canvasSize[1]/2.0
      dayFontFamily = "PT Sans"
      dayFontSize = "1.8pt"
      svgFileName = 'calendar_03.svg'
    
      # we will interpolate rainbow gradient through these points
      rainbowGradient = [[  0,  0,  0,239,255,255,  0,  0],  # Red
                 [254,248,246,194,  0,  0,211,254],  # Green
                 [255,193,  0,  0,  0,210,255,255]]  # Blue
      rainbowGradientPoints = [math.pi*2/7*0,
                   math.pi*2/7*1,
                   math.pi*2/7*2,
                   math.pi*2/7*3,
                   math.pi*2/7*4,
                   math.pi*2/7*5,
                   math.pi*2/7*6,
                   math.pi*2/7*7
                  ]
    
      #=======================================
      # Calendar circle parameters
      #=======================================
      k = 3.0 # multiplication koef.
      delta = 1.9 # first step in progression
      initRad = canvasSize[0]*0.3684 # initial size
      radiusProgression = [initRad]
      for i in range(4):
        nextValue = initRad-delta*pow(k,i)
        radiusProgression += [nextValue]
      R_dates = 1.2*canvasSize[0]*0.312
      R_days_end, \
        R_days_beg, \
        R_weeks_beg, \
        R_mounthes_beg, \
        R_seasons_beg = radiusProgression
      #R_weekend_end = R_days_beg + 20;
      R_weekend_end = R_days_end;
      # Stroke width
      stroke_k = 1.8
      stroke_thinest = 0.15
      dayLineStrokeWidth, \
        weekLineStrokeWidth, \
        mounthLineStrokeWidth, \
        seasonLineStrokeWidth = [0.1*(stroke_k**i) for i in range(4,0,-1)]
    
      weekendStrokeWidth = 6.7
    
      #=======================================
      # Filling mounth arrays
      #=======================================
      dayAngle = math.pi*2/365
      weekAngle = dayAngle*7
      mounthes = [u'января',\
            u'февраля',\
            u'марта',\
            u'апреля',\
            u'мая',\
            u'июня',\
            u'июля',\
            u'августа',\
            u'сентября',\
            u'октября',\
            u'ноября',\
            u'декабря'\
            ]
      mounthDays = [31,28,31,30,31,30,31,31,30,31,30,31] # days in each mounth
      yearDays = ["%d %s"%(i+1, mounthes[index]) \
                for index, m in enumerate(mounthDays) \
                for i in range(m)]
      # array with marks for yearDays:
      # 1 means first day of mounth
      # 2 means first day of mounth and of season
      allFirstDates = [ 0 if i!=0 else \
                1 if (index+1)%3!=0 else \
                2 \
                for index, m in enumerate(mounthDays) \
                for i in range(m)]
      mounthAngles = [d*dayAngle for d in mounthDays]
    
      #=======================================
      # Making svg and groups
      #=======================================
      dwg = svgwrite.Drawing(svgFileName, profile='tiny')
    
      textGroup = dwg.g(font_family=dayFontFamily, \
         font_size=dayFontSize,\
         text_anchor="start" )
      dayLineGroup = dwg.g(stroke_width=dayLineStrokeWidth, fill='none')
      weekLineGroup = dwg.g(stroke_width=weekLineStrokeWidth, fill='none')
      mounthLineGroup = dwg.g(stroke_width=mounthLineStrokeWidth, fill='none')
      seasonLineGroup = dwg.g(stroke_width=seasonLineStrokeWidth, fill='none')
      weekendGroup = dwg.g(stroke_width=weekendStrokeWidth, fill='none')
    
      #=======================================
      # Drawing in defined groups
      #=======================================
      for index, angle in enumerate(frange(0,math.pi*2,dayAngle)):
        # interpolation will help us to find
        # all necessary segments for every segment of circles
        colorTuple = (int(numpy.interp(angle, rainbowGradientPoints, \
                rainbowGradient[0])), \
               int(numpy.interp(angle, rainbowGradientPoints, \
               rainbowGradient[1])), \
               int(numpy.interp(angle, rainbowGradientPoints, \
               rainbowGradient[2])))
        color = "rgb%s"%(str(colorTuple))
        sinus =   math.sin(angle)
        cosinus = math.cos(angle)
        
        # Draw a week segment
        if (index-5)%7 == 0:
          weekLineGroup.add (dwg.line( (mid[0]-R_weeks_beg*sinus, \
             mid[1]+R_weeks_beg*cosinus), \
             (mid[0]-R_days_beg *sinus,mid[1]+R_days_beg *cosinus), \
             stroke=color) )
          # Draw a weekend
          sinus_weekend   = math.sin(angle-dayAngle)
          cosinus_weekend = math.cos(angle-dayAngle)
          weekendGroup.add (dwg.line( (mid[0]-R_days_beg*sinus_weekend, \
             mid[1]+R_days_beg*cosinus_weekend), \
             (mid[0]-R_weekend_end *sinus_weekend,mid[1]+R_weekend_end *\
             cosinus_weekend), \
             stroke=color) )
        #if (index-)
          weekLineGroup.add (dwg.line( (mid[0]-R_weeks_beg*sinus, \
                  mid[1]+R_weeks_beg*cosinus), \
             (mid[0]-R_days_beg *sinus,mid[1]+R_days_beg *cosinus), \
             stroke=color) )
        # Draw a mounth+season segments
        if allFirstDates[index]!=0:
          mounthLineGroup.add (dwg.line( (mid[0]-R_mounthes_beg*sinus,mid[1]+\
                  R_mounthes_beg*cosinus), \
             (mid[0]-R_weeks_beg *sinus,mid[1]+R_weeks_beg*cosinus), \
             stroke=color) )
          # Draw a season segments
          if allFirstDates[index]==2:
            seasonLineGroup.add (dwg.line( (mid[0]-R_seasons_beg*sinus,mid[1]+\
                    R_seasons_beg*cosinus), \
               (mid[0]-R_mounthes_beg *sinus,mid[1]+R_mounthes_beg*cosinus), \
               stroke=color) )
        # Draw a day segments
        dayLineGroup.add (dwg.line( (mid[0]-R_days_beg*sinus,mid[1]+\
                R_days_beg*cosinus), \
           (mid[0]-R_days_end *sinus,mid[1]+R_days_end *cosinus), \
           stroke=color
           ) )
    
        # Draw a day name
        if (index-4)%7 == 0 or (index-3)%7 == 0:
            fillColor = color #"rgb(255,255,255)"
            #fontWeight = "bold"
            weekendMargin = 2.0
        else:
            fillColor = "rgb(0,0,0)"
            #fontWeight = "normal"
            weekendMargin = 0
        wordGroup = dwg.g(transform="rotate(%f, %f, %f) translate(%f,0)" \
                %( math.degrees(angle+dayAngle+textAngleShift)+90, \
                mid[0], mid[1], +R_dates+weekendMargin ) \
                )
        wordGroup.add( dwg.text( '%s'%(yearDays[index]), \
                insert=mid, fill=fillColor \
                #,style="font-weight: %s;"%(fontWeight)
                ))
        textGroup.add(wordGroup)
    
        #=======================================
        # Dray a circle segments
        #=======================================
        sinus_end =   math.sin(angle+dayAngle)
        cosinus_end = math.cos(angle+dayAngle)
        dayLineGroup.add( dwg.line( (mid[0]-R_days_beg*sinus,  \
                mid[1]+R_days_beg*cosinus), \
          (mid[0]-R_days_beg*sinus_end,mid[1]+R_days_beg*cosinus_end), \
          stroke=color ) )
        weekLineGroup.add( dwg.line((mid[0]-R_weeks_beg*sinus,    \
                mid[1]+R_weeks_beg*cosinus), \
          (mid[0]-R_weeks_beg*sinus_end,mid[1]+R_weeks_beg*cosinus_end), \
          stroke=color ) )
        mounthLineGroup.add( dwg.line((mid[0]-R_mounthes_beg*sinus,   \
                mid[1]+R_mounthes_beg*cosinus), \
          (mid[0]-R_mounthes_beg*sinus_end,mid[1]+R_mounthes_beg*cosinus_end), \
          stroke=color ) )
        seasonLineGroup.add( dwg.line((mid[0]-R_seasons_beg*sinus,    \
                mid[1]+R_seasons_beg*cosinus), \
          (mid[0]-R_seasons_beg*sinus_end,mid[1]+R_seasons_beg*cosinus_end), \
          stroke=color ) )
    
      #=======================================
      # Simple circles for quick testing
      #=======================================
      #dayLineGroup.add( dwg.circle(center=mid, r=R_days_end, stroke='black' ) )
      #dayLineGroup.add( dwg.circle(center=mid, r=R_days_beg, stroke='black' ) )
      #weekLineGroup.add( dwg.circle(center=mid, r=R_weeks_beg, stroke='black' ) )
      #mounthLineGroup.add( dwg.circle(center=mid, r=R_mounthes_beg, stroke='black' ) )
      #seasonLineGroup.add( dwg.circle(center=mid, r=R_seasons_beg, stroke='black') )
    
      dwg.add(dayLineGroup)
      dwg.add(weekLineGroup)
      dwg.add(mounthLineGroup)
      dwg.add(seasonLineGroup)
      dwg.add(weekendGroup)
      dwg.add(textGroup)
    
      # As I didn't learn how to set document width and height, just draw a rect
      dwg.add(dwg.rect((0, 0), canvasSize, stroke='gray', fill="none"))
    
      dwg.add(dwg.text("2014", insert=(mid[0],mid[1]+4), \
              text_anchor="middle", font_family="PT Serif", font_size="10pt"))
    
      #=======================================
      # Finaly, draw it!
      #=======================================
      dwg.save()
    


    На выходе получаем такой вот SVG файл, который остаётся слегка доработать напильником в Иллюстраторе. А именно, увеличить документ до размеров А1, поправить кернинг числа 2014, увеличить апроши в мелких надписях, добавить внизу подпись.



    Оп-ля! Круглендарь готов. Делаем группу в контакте для получения обратной связи, пишем ридми для Гитхаба и статью на Хабр.

    Всем спасибо за внимание, буду рад вашим комментариям.

    Only registered users can participate in poll. Log in, please.

    Как вы представляете себе год?

    • 65.7%Круг, Новый Год сверху456
    • 14.8%Круг, Новый Год снизу103
    • 3.0%Круг, Новый Год справа21
    • 3.6%Круг, Новый Год слева25
    • 12.5%Спираль, Новый Год сверху87
    • 3.5%Спираль, Новый Год снизу24
    • 1.0%Спираль, Новый Год справа7
    • 1.6%Спираль, Новый Год слева11
    • 6.5%Другое (напишу в комментариях)45

    В какую сторону идум месяцы?

    • 79.4%По часовой стрелке494
    • 20.6%Против часовой стрелки128
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 72

      +19
      особенностью этого проета является минималистичность и пустота,

      И нечитаемость.

      Не нужно было переворачивать текст с левой стороны «вверх ногами». Лучше повернуть на 180 градусов.

      Зиму с ёлкой я бы расположил наверху. Все-таки люди привыкли, что на часах все начинается с 00:00, которые вверху

      Цвета можно было свести к таким: зима — синий, голубой; весна — зеленые; лето-желтый; осень — красные
      • UFO just landed and posted this here
          +3
          Тогда нужно в центре вместо 2014 кружок под дырку предусмотреть.
            +1
            И сверху стрелку сделать, независимую от календаря — крутишь календарь а она на день указывать будет, а-ля «Колесо фортуны».
              0
              Про стрелку думал, но пока что не нашёл способа сделать её промышленным способом надёжно, красиво и дёшево.
            0
            Идея хорошая, хотя я предполагал неподвижность календаря. Мне так проще ориентироваться в нём. Но ведь никто не мешает форкнуть.
            • UFO just landed and posted this here
            0
            лучше лето — красное (поспело)
            осень — жёлтая (листья)
              0
              Спасибо за ответ!

              Очень интересный вопрос про расположение Нового Года. У каждого в голове своя модель (не факт, что круглая). НГ может быть сверху (аналогия с часами), снизу (холодное — внизу, горячее — наверху), даже справа или слева. Или вообще непонятно где.

              Буду рад, если читатели хабра поделятся своими моделями. Также добавлю опрос.

              Про читаемость: пробовал разные варианты. Вариант, который вы предлагаете хорош. Однако, я выбрал другой как более плавный: в нём нет дополнительных стыков на границе полугодий. Сложно объяснить, это интуитивно.
              У опрошенных знакомых перевёрнутые названия месяцев затруднений не вызывают.
                +1
                Тогда уж добавьте опрос, в каком направлении идут месяцы. Например, у меня новый год наверху, слева февраль, март, апрель и далее против часовой стрелки. А у кого-то месяцы могут идти и по часовой. Так же интересно посмотреть на то, какой вариант преобладает.
                  0
                  Действительно, интенерсно. Добавил как новый опрос, чтобы не плодить кучу вариаций.
                  +1
                  Или вообще непонятно где.

                  Тут видимо как раз мой вариант: снизу текущая дата, месяцы идут против часовой стрелки. Касательную к текущей дате можно мысленно представлять как привычную временную ось: слева прошлое, справа — будущее.
                    0
                    Круто! Прекрасная модель, может быть действительно сделать вращающийся календарь.
                    +1
                    Был уже подобный вопрос
                    tema.livejournal.com/995570.html
                      0
                      Спасибо, интересная ссылка и тысяча комментариев по теме.
                  +2
                  Еще можно сделать «вечный» круглендарь — в виде спирали, начиная с года рождения и с доклеиванием новых витков снаружи. Для начала можно попробовать такое реализовать в софте, а если еще и интегрировать с социалками, почтой и другими хронологическими инструментами… Только тут важно хорошо оптимизировать его по памяти и подгружать только востребованный контент, иначе получится как с Google Wave.
                  +9
                  Хотелось бы увидеть хоть какой-то пример уже заполненного круглендаря за 2013 год, результат, так сказать.
                  +3
                  Мне вот на равне циклических календарей понравился вот этот. ilyabirman.ru/projects/forebruary/ (да простит меня автор за ссылку)
                    +1
                    Здесь основная суть не в цикличности, а в каракулепригодности, я так понял.
                      0
                      Может, невнимательно посмотрел, но кажется, что всегда будут присутствовать числа 29-30-31? Даже в феврале?
                        0
                        Да, есть такой там недочет.
                      +3
                      Случилось что-то интересное? Лихо дорисовываем круглендарь! К концу года будет любо-дорого смотреть.

                      Или Вас накроет жестокая депрессия из-за того, что он практически совсем пустой! Так что, не рекомендуется склонным к депрессии и просто тем, у кого мало что случается. :)
                        +3
                        Отдаленно похоже на календарь беременности. )
                        Кстати, выше высказана очень хорошая идея со спиралью.
                          +1
                          Да, после беременности и спираль пойдёт. (извините)
                          0
                          Прожекты расписывать…
                            0
                            Используя такой календарь, для периодических событий можно наловчиться многогранники рисовать.
                              +1
                              Всегда воспринимал год в виде синусоиды с минимумом функции в июле и максимумом в январе.
                                +1
                                Я, почему-то, представляю течение года против часовой стрелки… В отличии, как видно, от большинства. Почему так, интересно.
                                  0
                                  Может у вас часы без стрелок?
                                    +4
                                    Может быть, Вы — математик?
                                    image
                                    0
                                    отличная вешь
                                    может подскажете что в исходнике отвечает за направление? хочу для себя сгенерировать
                                    видимо я из тех 16 % :)
                                      0
                                      Быстро хорошего решения я не придумаю. Придумаю плохое:

                                      Если долго
                                      # -*- coding: utf-8 -*-
                                      import svgwrite, math, numpy
                                      
                                      def frange(x, y, jump):
                                        while x > y:
                                          yield x
                                          x += jump
                                      
                                      if __name__ == '__main__':
                                        # Calendar parameters
                                        dayAngle = math.pi*2/365
                                        textAngleShift = -(0.26*math.pi*2/365)-1*dayAngle
                                        canvasSize = (500,707)
                                        mid = canvasSize[0]/2.0, canvasSize[1]/2.0
                                        dayFontFamily = "PT Sans"
                                        dayFontSize = "1.8pt"
                                        svgFileName = 'calendar_CCW.svg'
                                      
                                        # we will interpolate rainbow gradient through these points
                                        rainbowGradient = [[  0,  0,  0,239,255,255,  0,  0],  # Red
                                                   [254,248,246,194,  0,  0,211,254],  # Green
                                                   [255,193,  0,  0,  0,210,255,255]]  # Blue
                                        rainbowGradientPoints = [math.pi*2/7*0,
                                                     math.pi*2/7*1,
                                                     math.pi*2/7*2,
                                                     math.pi*2/7*3,
                                                     math.pi*2/7*4,
                                                     math.pi*2/7*5,
                                                     math.pi*2/7*6,
                                                     math.pi*2/7*7
                                                    ]
                                      
                                        #=======================================
                                        # Calendar circle parameters
                                        #=======================================
                                        k = 3.0 # multiplication koef.
                                        delta = 1.9 # first step in progression
                                        initRad = canvasSize[0]*0.3684 # initial size
                                        radiusProgression = [initRad]
                                        for i in range(4):
                                          nextValue = initRad-delta*pow(k,i)
                                          radiusProgression += [nextValue]
                                        R_dates = 1.2*canvasSize[0]*0.312
                                        R_days_end, \
                                          R_days_beg, \
                                          R_weeks_beg, \
                                          R_mounthes_beg, \
                                          R_seasons_beg = radiusProgression
                                        #R_weekend_end = R_days_beg + 20;
                                        R_weekend_end = R_days_end;
                                        # Stroke width
                                        stroke_k = 1.8
                                        stroke_thinest = 0.15
                                        dayLineStrokeWidth, \
                                          weekLineStrokeWidth, \
                                          mounthLineStrokeWidth, \
                                          seasonLineStrokeWidth = [0.1*(stroke_k**i) for i in range(4,0,-1)]
                                      
                                        weekendStrokeWidth = 6.7
                                      
                                        #=======================================
                                        # Filling mounth arrays
                                        #=======================================
                                        weekAngle = dayAngle*7
                                        mounthes = [u'января',\
                                              u'февраля',\
                                              u'марта',\
                                              u'апреля',\
                                              u'мая',\
                                              u'июня',\
                                              u'июля',\
                                              u'августа',\
                                              u'сентября',\
                                              u'октября',\
                                              u'ноября',\
                                              u'декабря'\
                                              ]
                                        mounthDays = [31,28,31,30,31,30,31,31,30,31,30,31] # days in each mounth
                                        yearDays = ["%d %s"%(i+1, mounthes[index]) \
                                                  for index, m in enumerate(mounthDays) \
                                                  for i in range(m)]
                                        # array with marks for yearDays:
                                        # 1 means first day of mounth
                                        # 2 means first day of mounth and of season
                                        allFirstDates = [ 0 if i!=0 else \
                                                  1 if (index+1)%3!=0 else \
                                                  2 \
                                                  for index, m in enumerate(mounthDays) \
                                                  for i in range(m)]
                                        mounthAngles = [d*dayAngle for d in mounthDays]
                                      
                                        #=======================================
                                        # Making svg and groups
                                        #=======================================
                                        dwg = svgwrite.Drawing(svgFileName, profile='tiny')
                                      
                                        textGroup = dwg.g(font_family=dayFontFamily, \
                                           font_size=dayFontSize,\
                                           text_anchor="start" )
                                        dayLineGroup = dwg.g(stroke_width=dayLineStrokeWidth, fill='none')
                                        weekLineGroup = dwg.g(stroke_width=weekLineStrokeWidth, fill='none')
                                        mounthLineGroup = dwg.g(stroke_width=mounthLineStrokeWidth, fill='none')
                                        seasonLineGroup = dwg.g(stroke_width=seasonLineStrokeWidth, fill='none')
                                        weekendGroup = dwg.g(stroke_width=weekendStrokeWidth, fill='none')
                                      
                                        #=======================================
                                        # Drawing in defined groups
                                        #=======================================
                                        for index, angle in enumerate(frange(math.pi*2,0,-dayAngle)):
                                          #angle = -angle
                                          print angle, index
                                          # interpolation will help us to find
                                          # all necessary segments for every segment of circles
                                          colorTuple = (int(numpy.interp(angle, rainbowGradientPoints, rainbowGradient[0])), \
                                                 int(numpy.interp(angle, rainbowGradientPoints, rainbowGradient[1])), \
                                                 int(numpy.interp(angle, rainbowGradientPoints, rainbowGradient[2])))
                                          color = "rgb%s"%(str(colorTuple))
                                          sinus =   math.sin(angle)
                                          cosinus = math.cos(angle)
                                          
                                          # Draw a week segment
                                          if (index-5)%7 == 0:
                                            weekLineGroup.add (dwg.line( (mid[0]-R_weeks_beg*sinus, \
                                               mid[1]+R_weeks_beg*cosinus), \
                                               (mid[0]-R_days_beg *sinus,mid[1]+R_days_beg *cosinus), \
                                               stroke=color) )
                                            # Draw a weekend
                                            sinus_weekend   = math.sin(angle+dayAngle)
                                            cosinus_weekend = math.cos(angle+dayAngle)
                                            weekendGroup.add (dwg.line( (mid[0]-R_days_beg*sinus_weekend, \
                                               mid[1]+R_days_beg*cosinus_weekend), \
                                               (mid[0]-R_weekend_end *sinus_weekend,mid[1]+R_weekend_end *cosinus_weekend), \
                                               stroke=color) )
                                          #if (index-)
                                            weekLineGroup.add (dwg.line( (mid[0]-R_weeks_beg*sinus, \
                                                    mid[1]+R_weeks_beg*cosinus), \
                                               (mid[0]-R_days_beg *sinus,mid[1]+R_days_beg *cosinus), \
                                               stroke=color) )
                                          # Draw a mounth+season segments
                                          if allFirstDates[index]!=0:
                                            mounthLineGroup.add (dwg.line( (mid[0]-R_mounthes_beg*sinus,mid[1]+R_mounthes_beg*cosinus), \
                                               (mid[0]-R_weeks_beg *sinus,mid[1]+R_weeks_beg*cosinus), \
                                               stroke=color) )
                                            # Draw a season segments
                                            if allFirstDates[index]==2:
                                              seasonLineGroup.add (dwg.line( (mid[0]-R_seasons_beg*sinus,mid[1]+R_seasons_beg*cosinus), \
                                                 (mid[0]-R_mounthes_beg *sinus,mid[1]+R_mounthes_beg*cosinus), \
                                                 stroke=color) )
                                          # Draw a day segments
                                          dayLineGroup.add (dwg.line( (mid[0]-R_days_beg*sinus,mid[1]+R_days_beg*cosinus), \
                                             (mid[0]-R_days_end *sinus,mid[1]+R_days_end *cosinus), \
                                             stroke=color
                                             ) )
                                      
                                          # Draw a day name
                                          if (index-4)%7 == 0 or (index-3)%7 == 0:
                                              fillColor = color #"rgb(255,255,255)"
                                              #fontWeight = "bold"
                                              weekendMargin = 2.0
                                          else:
                                              fillColor = "rgb(0,0,0)"
                                              #fontWeight = "normal"
                                              weekendMargin = 0
                                          wordGroup = dwg.g(transform="rotate(%f, %f, %f) translate(%f,0)" \
                                                  %( math.degrees(angle+dayAngle+textAngleShift)+90, mid[0], mid[1], +R_dates+weekendMargin ) \
                                                  )
                                          wordGroup.add( dwg.text( '%s'%(yearDays[index]), \
                                                  insert=mid, fill=fillColor \
                                                  #,style="font-weight: %s;"%(fontWeight)
                                                  ))
                                          textGroup.add(wordGroup)
                                      
                                          #=======================================
                                          # Dray a circle segments
                                          #=======================================
                                          sinus_end =   math.sin(angle+dayAngle)
                                          cosinus_end = math.cos(angle+dayAngle)
                                          dayLineGroup.add( dwg.line( (mid[0]-R_days_beg*sinus,  mid[1]+R_days_beg*cosinus), \
                                            (mid[0]-R_days_beg*sinus_end,mid[1]+R_days_beg*cosinus_end), \
                                            stroke=color ) )
                                          weekLineGroup.add( dwg.line((mid[0]-R_weeks_beg*sinus,    mid[1]+R_weeks_beg*cosinus), \
                                            (mid[0]-R_weeks_beg*sinus_end,mid[1]+R_weeks_beg*cosinus_end), \
                                            stroke=color ) )
                                          mounthLineGroup.add( dwg.line((mid[0]-R_mounthes_beg*sinus,   mid[1]+R_mounthes_beg*cosinus), \
                                            (mid[0]-R_mounthes_beg*sinus_end,mid[1]+R_mounthes_beg*cosinus_end), \
                                            stroke=color ) )
                                          seasonLineGroup.add( dwg.line((mid[0]-R_seasons_beg*sinus,    mid[1]+R_seasons_beg*cosinus), \
                                            (mid[0]-R_seasons_beg*sinus_end,mid[1]+R_seasons_beg*cosinus_end), \
                                            stroke=color ) )
                                      
                                        #=======================================
                                        # Simple circles for quick testing
                                        #=======================================
                                        #dayLineGroup.add( dwg.circle(center=mid, r=R_days_end, stroke='black' ) )
                                        #dayLineGroup.add( dwg.circle(center=mid, r=R_days_beg, stroke='black' ) )
                                        #weekLineGroup.add( dwg.circle(center=mid, r=R_weeks_beg, stroke='black' ) )
                                        #mounthLineGroup.add( dwg.circle(center=mid, r=R_mounthes_beg, stroke='black' ) )
                                        #seasonLineGroup.add( dwg.circle(center=mid, r=R_seasons_beg, stroke='black') )
                                      
                                        dwg.add(dayLineGroup)
                                        dwg.add(weekLineGroup)
                                        dwg.add(mounthLineGroup)
                                        dwg.add(seasonLineGroup)
                                        dwg.add(weekendGroup)
                                        dwg.add(textGroup)
                                      
                                        # As I didn't learn how to set document width and height, just draw a rect
                                        dwg.add(dwg.rect((0, 0), canvasSize, stroke='gray', fill="none"))
                                      
                                        dwg.add(dwg.text("2014", insert=(mid[0],mid[1]+4), text_anchor="middle", font_family="PT Serif", font_size="10pt"))
                                      
                                        #=======================================
                                        # Finaly, draw it!
                                        #=======================================
                                        dwg.save()
                                      


                                      А если коротко:

                                      5c5
                                      <   while x < y:
                                      ---
                                      >   while x > y:
                                      11c11,12
                                      <   textAngleShift = -(0.26*math.pi*2/365)
                                      ---
                                      >   dayAngle = math.pi*2/365
                                      >   textAngleShift = -(0.26*math.pi*2/365)-1*dayAngle
                                      16c17
                                      <   svgFileName = 'calendar_03.svg'
                                      ---
                                      >   svgFileName = 'calendar_CCW.svg'
                                      63d63
                                      <   dayAngle = math.pi*2/365
                                      109c109,111
                                      <   for index, angle in enumerate(frange(0,math.pi*2,dayAngle)):
                                      ---
                                      >   for index, angle in enumerate(frange(math.pi*2,0,-dayAngle)):
                                      >     #angle = -angle
                                      >     print angle, index
                                      126,127c128,129
                                      <       sinus_weekend   = math.sin(angle-dayAngle)
                                      <       cosinus_weekend = math.cos(angle-dayAngle)
                                      ---
                                      >       sinus_weekend   = math.sin(angle+dayAngle)
                                      >       cosinus_weekend = math.cos(angle+dayAngle)
                                      
                                        0
                                        запустил, все работет, против часовой
                                        спасибо добрый человек
                                      0
                                      Как вы представляете себе год?

                                      Овал, текущая дата снизу.
                                        0
                                        Овал вертиальный или горизонтальный?
                                          0
                                          Очевидно зависит от текущей даты. :)
                                          Вообще, вытянут от зимы к лету, т.е. осень и весна длиннее. Почему так — не знаю.

                                          Кстати, если провести такой же опрос где-нибудь в июле, допускаю, что вариант «лето сверху» может быть намного популярнее, чем сегодня.
                                        +1
                                        У меня, почему-то, календарь всегда ассоциировался с прямоугольником. Причём месяцы идут против часовой стрелки, зима сверху. И ещё — самое странное — верхняя и нижняя стороны (зима и лето) длиннее боковых. Возможно это потому, что весна и осень всегда воспринимаются как некие переходные поры года, а лето и зима как-бы основные — 2 крайности в погоде.
                                          0
                                          А вот ещё вспомнил. Когда я отсчитываю месяцы, этот прямоугльник в уме воображаю как бы с обратной стороны (может даже объёмная картинка получается), т.е. месяцы идут уже по часовой стрелке. А если просто воображать год (календарь), то прямоугольник будто на плоскости и выглядит как описано выше.
                                            0
                                            А у меня наоборот в эллипсе весна и осень длиннее. У всех свои тараканы в голове командуют. :)
                                              0
                                              Ну хоть кто-то! Я тоже представляю год как прямоугольник. Правда, месяцы идут по часовой стрелке и зима снизу. Весна и осень у меня тоже немного короче зимы и лета. Причем если представляю год абстрактно, то прямоугольник ровный, а если думаю о текущей дате, он как бы искажается, и текущая грань представляется длиннее всех остальных.
                                              +1
                                              Спасибо за идею! Думаю прикрутить шаговый двигатель и повесить на стенку.
                                                +1
                                                Проезжал в обед мимо типографии — распечатал на А1. Вечером разрисую февраль, поделюсь как выглядит
                                                  0
                                                  Спасибо! Буду рад, если поделитесь фотографией в vk.com/kruglendar
                                                    0
                                                    поделились?
                                                  0
                                                  Повесить в туалете лист формата А1 — значит а) иметь большой туалет, б) повесить его на далекую от «думающего» стену, что помешает использовать фломастер в процессе «размышлений». Может, оно и лучше, но для туалета надо бы змейку или еще что-то, что плотнее использует пространство )
                                                    0
                                                    Рулон?
                                                      +1
                                                      А это идея. Провести статистический анализ по интенсивности использования бумаги и выпустить «календарь рулонный, отрывной, 1 неделя февраля, 54 метра». :)
                                                        0
                                                        Дошел в рулене до конца очередного «месяца», а этот месяц еще не кончился — «возьми себя в руки, не нарушай установленный тобой самим порядок!»
                                                    0
                                                    А у меня представление года в виде квадрата, по часовой, каждая сторона-время года. НГ соответственно где-то внизу(не посередине), весна слева, затем лето наверху и осень справа. А ещё при таком представлении в центре останется больше места для рисовашек =)
                                                      0
                                                      Тоже квадрат, только НовыйГод посередине сверху. Весна таки слева (против часовой стрелки)
                                                      0
                                                      Как вы представляете себе год?


                                                      Как прямую, с телепортом из конца в начало.
                                                        +2
                                                        Хм. С одной стороны — дико нечитаемо, неудобно как сам календарь, очень пусто. С другой — интересная идея. Можно было бы конечно попытаться уместить в формат А2 (у меня просто некуда вешать А1, что поделаешь).

                                                        Но вот меня это навело на мысль соеденить такой календарь с чем-то типа
                                                        Пример
                                                        image

                                                        Т.е. В середине Солнце, схематичные изображения Земли и т.д. Ну люблю я космос и астрономию, что поделаешь :)
                                                        К слову, более такой «техничный» или «научный» календарь — интересная идея. Можно еще какие-то данные выводить.
                                                          0
                                                          Можно развить. Очень интересная визуализация может получиться. На этом варианте я думал показывать фазу луны, но потом отказался от идеи.
                                                          0
                                                          Шыдевр!

                                                          rainbowGradientPoints = [math.pi*2/7*x for x in xrange(8)]

                                                            0
                                                            Будьте снисходительны, я — дизайнер.
                                                            А как надо было?
                                                              0
                                                              Я ж написал — list comprehension вместо повторения формулы 8 раз. Three or more — use «for».
                                                            +1
                                                            А меня в детстве бабушка приучила считать количество дней в месяце по костяшкам кулака, от туда, наверное, в голове, год выглядит, как синусоида.
                                                              0
                                                              Я тоже по костяшкам массив заполнял. Потом, правда, перепроверил на всяких пожарный.
                                                                0
                                                                Ещё один такой же как и я с годом в виде синусоиды)) а у вас минимум функции это зима или лето?
                                                                  +1
                                                                  У меня чуть по-другому, максимум, это длинный месяца (31 день), минимум короткие, правда немного нелогичное представление, я это и сам понимаю, июль и август, декабрь и январь, февраль, не укладываются, но ничего не могу с собой поделать.
                                                                    0
                                                                    Эта мнемоника хорошо работает. На переходе декабрь-январь и июль-август — разрывы фазы. Небольшая длина когерентности, в общем ,)
                                                                +1
                                                                Этот календарь нужен для летописи. На нем очень удобно отмечать события своей жизни, закрытия проектов в офисе и т.п. Как инструмент для слежением за датами этот календарь не подходит. Зато он крут тем, что его можно начать заполнять в любой момент!

                                                                Посему: даты размещать нужно по часовой стрелке, но никакой привязки к НГ не стоит делать. Более того, не стоит и писать год для календаря. Его можно начать в любой момент, в отличие от другого типа календарей. Стоит только представить фрустрацию человека, начинающего ежедневник в феврале, например, ууу…

                                                                Пишет скромный создатель кругового календаря в 2000 году. В прошлом году я также выпустил в свет вторую версию.

                                                                Кстати, я еще пришел к тому, что этот календарь очень легко кастомизируется, на радость тем, кто хочет себе нечто особенное. Вот, мой друг держит свеженапечатанный экземпляр для биофака университета Южной Каролины: instagram.com/p/aN0godruOc/

                                                                Крайне рад, что, оказалось, у меня есть однодумцы. Я тут побурчал, но на самом деле клево получилось ;-)
                                                                  0
                                                                  Версия для биофака действительно крутая! И ДНК хорошо обыгралась, и монохромность пошла на пользу. Макет сохранился? Я бы повесил на стенку.
                                                                    0
                                                                    Макет сохранился, но на работе. Как приду — выложу, но, увы, только в ознакомительных целях, ибо он таки custom shop для одного человека в одном экземпляре.
                                                                      +1
                                                                      Вот тут можно посмотреть.
                                                                        0
                                                                        Спасибо.
                                                                    0
                                                                    Было бы любопытно сделать такой на D3.js с возможностью кастомизации и печати прямо из браузера.
                                                                      0
                                                                      Ого! Вдохновился, спасибо. Хочу как-нибудь сделать версию календаря по мотивам этого скрипта. Интересно, как проще на питоне сделать физическую симуляцию?

                                                                    Only users with full accounts can post comments. Log in, please.