Самые простые фракталы на JavaScript

Представляю сообществу страничку на JavaScript, которая позволяет строить, рисовать, создавать простые фрактальные фигуры, основанные на самоподобии. На самом деле это мой первый опыт использования HTML/CSS/JS. При обширном опыте программирования, я до сих пор пропускал веб-разработку. А поскольку, по моим представлениям, самый удобный способ научиться программировать — это сделать какой-нибудь проект, вот он мой фрактальный HelloWorld.




Общая идея проста. Берется какая-нибудь линия, состоящая из отрезков, то есть кусочно-линейная. Назовем ее базовой линией. Затем каждый из отрезков заменяется на копию базовой линии соответствующим образом масштабированную и повернутую. Далее заменяется каждый из сегментов получившейся линии, и процесс продолжается пока не надоест. Проиллюстрирую на картинках. Пример базовой линии:



Первая итерация:



Вторая:



Программка позволяет создавать и изменять базовую линию: добавлять и удалять вершины, двигать их, сразу же смотреть что из этого получается. Кроме того, производить замену сегмента на копию базовой линии можно по-разному. Можно, например, перед заменой отразить базовую линию относительно одной из осей (той, которая соединяет начальную и конечную точки). Конечно, можно было бы отразить и относительно перпендикулярной оси, но я реализовал только первый вариант. Будет или нет отражение показывается цветом базовой линии:



А вот способы управления и контроля.
  • Shift + левая кнопка мыши на базовой линии — добавление новой вершины;
  • Ctrl + ЛКМ на вершине — удаление вершины;
  • ЛКМ на вершине — перемещение;
  • ЛКМ на сегменте — использование отражения на данном сегменте;
  • ЛКМ на пустом месте — передвижение всей фигуры целиком.



И несколько картинок:





Напоследок несколько слов о коде. Конечно, после C++/Matlab/Python я был весьма удивлен представлению объектов в JS. И отсутствию классов, и глобальным переменным. В конце концов, я заключил весь код в две функции. Первая создавала объект фрактала и выполнена по следующей схеме с использованием замыкания:

function fracObject() {
    // объект для приватных данных
    var own = {};
    // и для публичных
    var that = {};
    // ... здесь они заполняются ...
    // а возвращается только публичный
    return that;
}


Пока не знаю как к этому добавить наследование, как корректно использовать this. Но это в будущем, для этого проекта наследование было бы уже лишним. Вторая функция загружается после body.onload и реализует взаимодействие с пользователем.

Ссылка на проект в GitHub: https://github.com/nordwinder/frac-js

А тем, кто дочитал до конца, пожелаю красивых фракталов.

UPD: Заменил рекурсивный вызов на обычную, хотя и более сложную функцию. Сдается мне, стало быстрее работать. Кроме того, теперь за один раз рисуется не более 10 тысяч отрезков. Затем следует небольшая пауза — браузеру обработать события, посмотреть не ушел ли пользователь. Добавил прогресс бар и кнопку отмены. Теперь вешать браузер не должно даже на самых сложных и запутанных линиях.
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 41
  • +1
    А что станет с прямой линией?

    p.s. понимаю, глупый вопрос
    • +1
      Самоподобие)Предполагаю прямая линия?
      • +7
        Ну да, прямая линия заменяется на прямую линию, потом снова… Ничего увлекательного. )
        • 0
          Именно поэтому не стоило её делать по умолчанию. Пришлось поломать голову, прежде чем дошло, что надо добавить нодов, чтобы что-то получилось.
    • 0
      У меня от этой штуки Firefox умер, когда я поменял «Fractal iterations» на 5 (два раза пробовал).
      Как можно этого избежать?
      • +1
        Странно, я тестировал на Firefox под убунтой. На какой версии падает, на какой платформе, сколько точек было в базовой линии?
        • 0
          20 точек. Видимо происходит расчет (одно из ядер ЦП загружено на 100%), но вешается весь браузер.
          Firefox 22.0, Window 7 Enterprise 64-bit, Intel Core i5-2540M 2.60 GHz, 16 GB RAM

          Расчеты могут быть требовательны к ресурсам, но хотелось бы иметь возможность их прервать не убивая браузер. :-)
          • +1
            Ну да, 20 точек в 5 степени — 3.2 миллиона точек. С одной стороны много, с другой стороны — современные компьютеры умеют и не такое. Можно вычисления вынести отдельно и добавить кнопочку cancel. Тоже забавная задача, может сегодня вечером займусь. А может html canvas не готов к такому количеству lineTo.
            • 0
              Спасибо! :-)
              • 0
                В убунте фокс наверняка 64битный, а в винде нет. Он случайно в лимит в 2гб рамы не стукается?
              • +1
                Убрал рекурсию. Добавил прогресс бар и кнопку отмены. Теперь рисует не более 10 тысяч отрезков за раз. Вешать браузер не должно. :)
          • 0
            Знаю, что скажу бред, но фрактал из шапки чем-то напоминает Game Of Life.
            • +3
              Что-то в Хроме никаких фракталов не видно. Просто пустой квадрат.
              • 0
                Shift + левая кнопка мыши на базовой линии — добавление новой вершины;
                Ctrl + ЛКМ на вершине — удаление вершины;
                ЛКМ на вершине — перемещение;
                ЛКМ на сегменте — использование отражения на данном сегменте;
                ЛКМ на пустом месте — передвижение всей фигуры целиком.
                • +1
                  Базовой линии вообще не видно в Хроме, некуда кликать.
                  • 0
                    Значит перерисовка на JS вообще не запускается. Хотя я уже на двух компах проверил работу в Хроме, на обоих удачно. Эх, сложная это штука — веб-дев.
                  • 0
                    Подтверждаю, пустой экран. GoogleChrome 28.0.1500.72 m, Windows 8 Профессиональная 6.2.9200
                    • 0
                      Интересно. У меня сейчас запущена эта же версия Хрома, правда на старенькой WinXP. Все работает. Может нет доступа к frac.js?
                      • +1
                        Обновите -> откройте другую вкладку -> верните текущую. Мне помогло :-)
                        Chrome 28 Win8
                    • 0
                      Та же фигня. Пусто
                    • 0
                      Интересно.
                      А что если на каждой итерации брать не первоначальную фигуру в качестве продолжения фрактала, а фигуру, получающуюся на n-1 итерации? Конечно, он будет очень быстро расти, но какая при этом будет образовываться форма?
                      • 0
                        Если я правильно понимаю, то будет та же фигура, просто 1, 2, 4, 8, 16-й шаги и так далее.
                        • 0
                          Да, действительно. Не подумав написал.
                      • 0
                        Кстати, чтобы самому ничего не скачивать, можно было бы сразу в jsfiddle.net разместить для демонстрации (правда там почему-то не работает). Также у вас есть небольшие ошибки в скрипте.
                        • 0
                          Небольшие ошибки?
                          • 0
                            Ну да. Я проверил с помощью JSHint на jsfiddle. Пропущена точка с запятой в getBaselineSegmentIndex и прочие мелочи.
                        • 0
                          Для того, чтобы имитировать класс, вам следовало бы определять методы внутри прототипа конструктора, например так:
                          fracObject.prototype.redraw = function () { ... };
                          fracObject.prototype.getBaseline = function () { ... };
                          fracObject.prototype.getInverse = function () { ... };
                          

                          Экземпляр класса fracObject инстанцировать с помощью оператора new
                          document.body.onload = function() {
                             var frac = new fracObject();
                             ...
                          };
                          

                          Ну и производить инициализацию внутри конструктора. Правда в таком случае, в отличии от вашего, свойства будут доступны снаружи.
                          function fracObject() {
                             this.baseline = [ { x: 50, y: 450 }, { x: 550, y: 450 } ];
                             this.normalized = [];
                             this.fracDepth = 0;
                             ...
                          };
                          

                          Конструкторы, кстати, принято именовать с большой буквы.
                          • +2
                            Как пользоваться конструкторами и прототипами я прочитал… Потом еще раз прочитал… Потом решил, что пойму это как-нибудь в следующий раз, а пока сделаю функцию, которая создает два объекта: один возвращает, а второй замыкает. Так что fracObject — это именно функция и маленькая буква здесь к месту.
                            Возможно уже завтра озарение настигнет меня и я пойму, что все сделал неправильно.
                          • 0
                            в сафари под макосью очень печально медленно
                            • 0
                              Есть проблема: можно добавить одну ноду и вытянуть её так, что длина рёбер будет больше, чем расстояние между концами ломаной. Условие «as needed» никогда не сработает, т.к.отображение получилось несжимающее, и вообще говоря это уже не фрактал.

                              Если сделать одно ребро «почти равным» расстоянию между точками, тоже видно, что логика «готовности» у вас хромает. Браузер так можно и на пять минут подвесить.

                              Разумно было бы ограничивать не число итераций, а останавливать разбиение ребра, когда его длина становится равной 1 px, т.е. более тонкую картинку уже невозможно отобразить.
                              • 0
                                «as needed» как раз повторяет итерации до тех пор, пока длина очередного отрезка не станет меньше 3 px. Но при этом не более 10 итераций в глубину, что позволяет остановиться в случае несжимающих отображений. Так что алгоритмически обработка в любом случае конечна. Но увы, конечная не значит быстрая. То, что программка при достаточном числе узлов и итераций может ввести в кому браузер мы уже выяснили, да…
                              • 0
                                На Mac клик с зажатым Ctrl считается кликом правой кнопкой мыши. К сожалению, похоже, быстро сделать обработку Cmd не получится, поэтому, наверное, самым легким решением будет добавить altKey параллельно с ctrlKey. Спасибо :)
                                • 0
                                  Попробовал добавить alt. На линуксе alt+click перемещает окна, на винде — никак не реагирует. )
                                  • 0
                                    Попробуйте использовать e.keyCode. Вот всевозможные коды для клавиши cmd: 91, 93, 157, 224. Первые два для webkit, остальные, к сожалению, уже не помню от чего.
                                • 0
                                  del
                                  • 0
                                    Было бы здорово, если бы предусматривалась возможность генерировать фракталы, которые задаются не базовыми линиями, а сжимающими отображениями. Скажем, изначально есть прямоугольник, мы его сжимаем и двигаем, получаем другой прямоугольник. Потом возвращаемся к изначальному, снова сжимаем и двигаем. Таким образом мы задаем систему сжатий. Потом, как гласит фрактальная геометрия, если взять любой компакт (к примеру, любую точку), и применять к ней эти отображения (сжатия и сдвиги), потом применять их к тем точкам, которые получились, и так далее — то будет вырисовываться фрактал. А ускориться можно согласно теории хаоса на фракталах — возмем просто случайную последовательность из индексов сжимающих отображений и будем применять к точке, должен получиться тот же фрактал.
                                    • +2
                                      Классная идея с рисованием в браузере!
                                      Сразу вспомнил студенчество и свою подобную десктопную программу в качестве курсовика. Только я делал задание начальной аксиомы и правил трансформации в виде текста. Плюс для красоты некоторых фракталов реализовал полутона.
                                      image

                                      Если добавить возможность прерывать линии, то можно получить другие интересные узоры, например: мозаика

                                      Если кому интересно — вот программа с примерами разных фракталов в каталоге Samples.
                                      • 0
                                        Фрактал, это когда фигура повторяет сама себя, каким образом тогда в «мозайке» из прямоугольника получился квадрат в центре?
                                        • 0
                                          Во-первых, у вас неверное определение фрактала. Бывают нерегулярные фракталы.
                                          Во-вторых, ничего удивительного нет в «квадрате из прямоугольника». Вон, из ломаной же получаются картинки вроде той, что выше.
                                          • 0
                                            Для фракталов на базе L-систем можно. Вообще зависит от «навороченности» правила и возможных поддерживаемых конструкций рисования. Их может быть достаточно много.
                                            en.wikipedia.org/wiki/L-system#Example_7:_Fractal_plant

                                            Example 7: Fractal plant
                                            variables: X F
                                            constants: + − [ ]
                                            start: X
                                            rules: (X → F-[[X]+X]+F[+FX]-X), (F → FF)
                                            angle: 25°
                                            Here, F means «draw forward», — means «turn left 25°», and + means «turn right 25°». X does not correspond to any drawing action and is used to control the evolution of the curve. [ corresponds to saving the current values for position and angle, which are restored when the corresponding ] is executed.

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