Как ниндзя прототипы делал. Ninjamock.com — дизайнер интерфейсов

    Здравствуйте! Мы — команда ниндзя-разработчиков проекта ninjamock.com. Ninjamock.com — это еще один онлайн-дизайнер скетчей и прототипов. Проект полностью написан на javascript и HTML5, серверная часть — на ASP.NET MVC.

    За год работы над проектом мы наступили на огромное количество граблей и накопили бесценный опыт разработки больших приложений на JavaScript, которым и хотим поделиться. В этой статье мы расскажем, как прототип из одного файла index.html перерос в полноценный проект с более чем 250 классами и 60000 строк кода (не считая сторонних библиотек). Также, в общих чертах опишем нашу архитектуру и детально опишем реализацию отрисовки на клиенте.


    UPD: Следите за апдейтами на нашем твиттере или странице фб



    Начало


    Мы все работаем (всё еще работаем) в одной крупной компании, и как-то так совпало, что нам это надоело в один момент и мы решили захватить мир начать проект, который бы позволил нам работать на себя. Так, одним осенним днем мы собрались в баре выпить по кружке «чая» и обсудить, как это сделать. Где-то после N-й кружки наш гениальный план был готов:

    • Пишем лучший скетч-дизайнер
    • ???
    • Получаем прибыль

    Позже выяснилось, что мы не оригинальны и этот план придумали до нас — бизнес-план гномов.

    Под скетч-дизайнером мы подразумеваем приложение, в котором можно рисовать скетчи, вайрфреймы или мокапы приложений, а также, делать простые кликабельные прототипы. Главная наша целевая аудитория — это программисты, дизайнеры, бизнес-аналитики и небольшие компании, занимающиеся разработкой мобильных приложений, которым нужно быстро нарисовать дизайн приложения, или же протестировать прототип.

    Главным конкурентом мы считали хорошо известный balsamiq.com, чьи финансовые отчеты и вдохновили нас начать работать в этой области. Но, похоже, что мы были не одни, кто думал так же, и в течение года появилось несколько похожих проектов.

    В отличие от balsamiq, который написан на flash, мы решили все делать «правильно» и писать на HTML5, чтобы можно было работать на всех платформах (и потому, что это был модный тренд на тот момент).

    Еще одно наше отличие от balsamiq состоит в том, что мы ориентируемся на специфические платформы (iPhone, iPad, Windows Phone, и т.д.). То есть, бальзамик — это универсальная платформа для рисования чего угодно, поэтому у них нет семантики специфичной конкретным платформам. Зачем такая семантика нужна? Например, для генерации кода по нарисованному дизайну. У нас все контролы ведут себя более-менее как настоящие.

    Архитектура проекта на текущий момент


    Серверная часть довольно проста и реализована на ASP.NET MVC; там, наверное, не о чем особо рассказывать. Большая часть кода у нас находится на клиенте и написана на JavaScript. Когда мы начинали проект, мы смотрели в сторону CoffeeScript, но посчитали, что инфраструктура для него на тот момент была достаточно сырой, так что мы решили писать все на чистом JavaScript.

    Как и все уважающие себя JavaScript разработчики, мы изобрели не один велосипед и написали несколько своих фреймворков :) Например, у нас свой способ создания классов — там есть несколько интересных моментов, о которых мы расскажем в одной из следующих статей. Сейчас же, с появлением TypeScript, мы, скорее всего, перейдем на него, как только появится поддержка в WebStorm.

    На клиенте у нас есть одна основная страница, на которой используется весь JavaScript. Из сторонних фреймворков, мы используем jQuery и knockout.js. Однако, архитектурно мы решили жестко не завязываться на сторонние фреймворки, поэтому у нас есть всего несколько платформо-зависимых классов, в которых разрешено их использование.

    Код клиента включает в себя:
    • Объектную модель дизайн-элементов, т.е., базовые классы для наших контролов.
    • Ядро отрисовки. Сюда входят классы обработки событий мыши и клавиатуры. Эти классы отвечают за нахождение и перемещение элементов по координатам, составление порядка отрисовки элементов, а также, вызов самой отрисовки для каждого элемента.
    • Дизайн-элементы (контролы) для конкретных платформ (пока что, только для iPhone). Каждый контрол сам решает, как себя отрисовывать в заданных координатах. У текущих контролов отрисовка «захардкоджена» в код самого контрола — например, в коде «кнопки» мы рисуем прямоугольник, закрашиваем его цветом, потом сверху рисуем текст, выравниваем по середине и т.д. Однако, для отрисовки новых контролов (которые еще не выпущены) мы решили поступить иначе — использовать собственный дизайнер для рисования полноценных контролов. Получилось довольно интересно и мы об этом расскажем более детально в одной из следующих статей.Частично этот функционал уже доступен, можно выбрать один или несколько элементов, затем кликнуть правой кнопкой и выбрать Assets -> Convert to asset. После этого новый элемент появляется в панели слева. И по двойному клику на элемент можно редактировать его шаблон.
    • Модели представления (ViewModel) для страницы и диалогов. Это платформо-независимые классы, на которые завязаны шаблоны knockout.js.
    • Классы привязки ядра к платформе, на которой запущено наше приложение. Здесь у нас находится код подписки на события мыши и клавиатуры; этот код перенаправляет события в ядро для последующей обработки. Например, на компьютере, на iPad или на iPhone подписка на события делается по-разному; маки и PC отличаются сочетаниями клавиш, и т.д.
    • Расширения. Проектируя наш код, мы полагались на принцип открытости/закрытости, поэтому в расширениях реализован тот функционал, без которого в принципе можно было бы обойтись: например, снаппинг элементов, подсветка контейнера при дропе элемента, автосохранение проекта в localStorage. Всего у нас 17 расширений.

    Но все начиналось гораздо проще…

    Первый прототип


    Первый прототип был написан за несколько дней. В нем, как и должно быть в прототипе, все было очень просто. Наши контролы были HTML-элементами. Например, прямоугольник — это просто div, клавиатура телефона — это img, а элементы посложнее, там где нужны градиенты (например таб-бар или тулбар), — это canvas. Все элементы имели абсолютные координаты, положение элементов относительно друг друга задавалось через css-свойство z-index. Перемещение элементов было реализовано через jquery.draggable.

    Все контролы размещались в div-элементе, который представлял собой нашу виртуальную страницу, т.е., он был шире и выше, чем рабочая область (для обеспечения скроллинга), а при масштабировании его размер соответствующим образом изменялся.
    Главными плюсами такого подхода являются простота реализации и отличный скроллинг элементов, который браузер делает за нас, ну, и много других плюшек.

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

    Первым камнем преткновения стал банальный зум, который мы так и не смогли нормально реализовать. Собственно, у нас было два варианта:

    • CSS-свойство zoom — работает отлично, если вам нужно уменьшить элемент. С увеличением же есть проблема: все наши элементы — векторные, большинство из них было нарисовано на канвасе. При увеличении канваса через css, его контент масштабируется растрово, в то время как нам был нужен векторный зум. Пример того, как это не работает, можно увидеть тут: jsfiddle.net/MzGpe/3
    • «Ручной» зум, когда нужно пройтись по всем элементам и поменять их положение и размер, а также перерисовать всё содержимое всех канвасов с учётом нового масштаба. Но мы так и не смогли добиться плавной отрисовки — все элементы ужасно (последовательно) прыгали в момент масштабирования.

    Удивительно, но ни у одного из конкурирующих приложений, реализованных на HTML (fluidui.com, gomockingbird.com, moqups.com), нет масштабирования.

    Второй прототип


    Нашим решением стало выбросить все HTML элементы и заменить их одним большим канвасом, на котором все и рисовалось. Размер канваса был равен размеру нашей виртуальной страницы. Поэтому скроллинг работал как и раньше но теперь появилась возможность все плавно масштабировать.

    Дополнительным преимуществом такого подхода является легкий способ генерации картинки из канваса — это позволяет нам делать превьюшки страниц, используя метод canvas.toDataUrl. Причём, все это выполняется на клиенте и не нагружает сервер. Кроме этого, у нас появилась возможность обработки отдельных пикселов изображения (что в будущем позволит добавить интересные графические инструменты).

    Рабочая область нашего приложения с 15-кратным масштабированием:



    Однако и тут все оказалось не так просто. При любом перемещении элементов мышью (а это наиболее часто используемое действие), канвас со всеми контролами перерисовывался целиком, что значительно сказывалось на производительности приложения. Решилось это довольно просто — мы добавили еще один канвас поверх первого. Так у нас получилось 2 слоя (изначально их было 3 но это другая история :) ). Первый слой содержал более-менее статичную картинку, которая относительно редко перерисовывалась, в то время как на втором канвасе рисовались временные объекты и различные эффекты, такие как линии привязки и подсветка элементов при наведении. Результат удовлетворил нас почти полностью.



    Однако, опять нашлись проблемы, которые показали несовершенство данного подхода. При масштабировании, размер изображения, а, соответственно, и размер канваса, увеличивался. По умолчанию, размер нашей дизайн-страницы равен 1024х768. При 4-кратном увеличении, размер канваса равен 4096х3072, и уже не каждая машина справляется с отрисовкой (с приемлемой скоростью). Более того, на нескольких машинах при таком увеличении стали появляться странные артефакты в виде полос и разноцветных точек. А ведь 4-кратное увеличение — это далеко не предел.

    В результате, мы пришли к решению, которое и используем сейчас. Это все те же два канваса, но их размер теперь равен не размеру дизайн страницы, а размеру видимой части страницы на экране. Из-за этого нам пришлось отказаться от стандартного скроллинга и учитывать позицию скроллинга при отрисовке.

    При таком подходе все работает отлично, за исключением одного небольшого минуса — скорость скроллинга незначительно упала по сравнению с предыдущими вариантами.

    На скриншоте в начале статьи можно увидеть, как наш проект сейчас выглядит. Вживую его можно посмотреть здесь: ninjamock.com.

    Эпилог


    Сейчас мы активно работаем над увеличением количества контролов, поддерживаемых платформ (скоро появится пооддержка ipad, windows phone, surface, а так же десктоп приложений) и одновременно думаем над вторым пунктом нашего бизнес плана. Будем рады услышать любой фидбек и ответить на любые вопросы по нашему проекту.

    Команда проекта ninjamock — pastorgluk, Денис и Headwithoutbrains.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 32

      +2
      А что, если сделать скроллинг wireframe'ным(то есть только контуры блоков), а отрисовка по завершению движения?
        +1
        Это тоже вариант, но согласитесь, выглядело бы не совсем красиво. И я думаю смена полной прорисовки на контурную при каждом скроллинге могла бы нервировать
          0
          Как вариант — переключение режимов при скроллинге. Не у всех же производительные системы, а по идее код не должен стать сильно сложнее
        +2
        и ни слова про Android…
          +1
          Андроид на данный момент так же в наших приоритетах, просто банально не хватает рук и времени на всё :)
            +3
            Wireframe'ов для iOS хоть попой жуй, если бы вы изначально сделали для Android, то заняли бы свободную нишу, а так ваш проект один из…
              +1
              Никогда не поздно. Нашей задачей первоочередной было создание как раз фреймворка для удобного построение контроллов. Мы с это задачей справились и сейчас кинули силы на прорисовку контроллов. Но спасибо вам и djvu за подсказку.
                0
                Дык автор так прямо и написал:
                Ninjamock.com — это еще один онлайн-дизайнер скетчей и прототипов

                Я воспринял это как «мы ничем от них не отличаемся». И только после прочтения пр канвас и масштабирование полез смотреть, потому что сам сейчас работаю с канвасом и его масштабированием.
                  0
                  Удален
              +2
              Скажите, а почему Linux не поддерживается? Я думал, что основное преимущество web приложений — кросплатформ.
              LogJS: uncaught exception: Not supported platform

                +2
                Нам очень стыдно, что мы такое пропустили :( Но мы это прямо сейчас пофиксим и выкатим новый релиз. Спасибо вам за замечание!
                +1
                Какая система монетизации у бальзамика и какую хотите использовать вы?
                  +1
                  В целом у бальзамика есть два источника прибыли — подписки, где ограничение по пользователям и проектам, а так же десктоп версия.
                  Наша идеалогия, в том что для индивидуальных пользователей весь функционал, который не слишком грузит сервера — бесплатный.
                  Скорее всего мы выберем такую же модель монетизации, как у бальзамика с уклоном в большую «бесплатность».
                  +3
                  Metro проникает в ряды, что не может не радовать :)

                  Некоторые моменты, большей частью по интерфейсу:
                  1. Расстраивает отсутствие автодоводки размещаемого элемента к нужным границам.
                  2. До конца непонятно, как при работе над, допустим, iOs переключиться к отображению под десктопы.
                  3. При изменении ориентации на ландшафтную в Chrome 18.0.1025.1634 Windows 7 контент не перестраивается, а остается статичным, как при портретной ориентации.
                  4. Это уже вкусовщина, но, мне кажется, доступного пространства вокруг слишком много, возникает ощущение, что оно несет какую-то функциональную нагрузку.
                  5. И тоже субъективно — по мне, с количеством бордером чуть-чуть переборщили.
                  6. Попытка удаления элемента не задумываясь происходит попыткой драга объекта на левую колонку :)

                  За поддержку горячих клавиш респектище :)
                    0
                    Спасибо за отзыв :)
                    1. Вы бы не могли уточнить? У нас есть автодоводка(снаппинг) на данный момент
                    2. Мы подумываем над автоматической конвертацией проектов, но это не тривиальная задача
                    3. Спасибо, учтем!
                    4. 5. Мы старались сделать дизайн редактора как можно менее ярким, что бы он не отвлекал при работе.
                      0
                      Хм, значит на моей машине снаппинг в таком случае не работает — любой элемент легко можно выдвинуть на три-четыре пикселя за границы рабочей области, например.

                      Кстати, багрепорт.
                      1. Открыл в первый раз проект, что-то поделал, закрыл вкладку.
                      2. Открыл второй раз, выбрал «Decide later», закрыл.
                      3. Открыл в третий, выбрал «Open», открылся самый первый проект, а не последний.
                        0
                        По поводу снаппинга разобрались, спасибо, очень полезное замечание!
                        Багрепорт учтем. Автосейв иногда слегка сбоит. Спасибо :)!
                    +1
                    Ресайз картинок со свойством stretch происходит не при протягивании рамки, а уже после. Достаточно ненаглядно. Если сделаете плавный ресайз при протягивании — будет значительно удобнее работать с картинками.

                    Плюс показалось очень странным, что скролл работает как вверх-вниз, а не как больше/меньше.

                    А вообще, хорошо что собрались и сделали. Свой кусочек пирога полюбому откусите!
                    +1
                    Десктопные вещи там не делаются? Сайты и приложения?
                      0
                      Изначально мы ориентировались только на мобильные приложения, но сейчас постараемся покрыть и сайты и десктоп. Весь вопрос только в прорисовке контроллов.
                        +1
                        А интерактивность элементов будет? Как в Аxure, чтобы сделать кликабельный интерфейс?
                          0
                          На данный момент уже есть возможность связывать кнопки со страницами. Можно так же у кнопки выбрать тип — Зона, задать ссылку, и при превью, она будет невидима, но область будет кликабельна.
                          Так же в планах добавить состояния элементов (хавер, маусовер и т.д.) что бы добавить вот эту интерактивность.
                      +3
                      Все, кто когда-либо использовал программы Adobe так же скажут вам спасибо за:
                      Shift + Arrows — перемещение на 10 пикселей
                      Ctrl + Arrows / Ctrl + drag — дублирование с перемещением
                      Ctrl + Shift + Arrows — дублирование и перемещение на 10 пикселей
                      Hold Space — перемещение холста
                      Ctrl + Click — увеличение масштаба
                      Ctrl + Alt + Click — уменьшение масштаба

                      Ну и остальные тоже можно :) Но это прям то что очень просится.
                      Кстати говоря если уж даете работать с цветами, то стоит сделать индивидуальную палитру, в которую можно было бы легко добавить свои цвета / градиенты. Тоже очень помогает в подобной работе.
                        0
                        Благодарю за советы. Добавим хоткеи.
                        Да, планы о палитре были, и судя по нашему опыту, она нужна :)!
                        +1
                        Прочитал «до ката», понял, что ничего в статье не пойму. Перешел по ссылке, потыкал 10 минут. Круче чем LucidChart, который сейчас использую. Спасибо!
                          +1
                          Неплохо, добавил в букмарки.
                            +1
                            Субъективные замечания:
                            1. На странице создания проекта hover-эффект при выборе типа выглядит очень резко из-за инвертирования цветов
                            2. Кнопка Save с изображением дискеты — это анахронизм, от нее нужно избавится вообще. Постоянное автосохранение взамен.
                            3. Комбинации клавиш для рисование примитивов (окружность и прямоугольник) — shift только фиксирует форму, можно ещё для квадрата, круга и круга от центра (хотя может это и излишек для мокап-инструмента)
                              0
                              1) Передадим дизайнеру!
                              2) Хорошее замечание. Мы целились в такую же реализацию, как и у гугл документов, но на данный момент органичены вычислительными возможностями сервера :) Но скоро мы введем версионность документов, и так же автоматическое сохранение.
                              3) Спасибо, учтем!
                              +2
                              Кто такой Alexander Stepanishchev, и почему я вижу его в своём профиле? (авторизовался через твиттор)
                              Бага или фича
                                +1
                                Спасибо, что поправили. Оперативно.
                                Удачи вам и вашему сервису.
                                Ждём Андроид.
                                +1
                                Мой босс начал прототипитировать версию нашего продукта для айфона. После того как он перепробовал множество разных спец тулов (balsamiq, axure etc), он скачал файл для фотошопа с айфоновыми контролами и начал работать в фотошопе, т.к. это привычная среда для него.
                                Сегодня я показал ему ninjamock. Уже через полчаса я услышал с его места фразу:
                                «Oh my god, this is so much easier then anything I've tried before. It is brilliant.»

                                Спасибо за отличную тулзу =)

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

                                Самое читаемое