- PVSM.RU - https://www.pvsm.ru -
Здравствуйте! Мы — команда ниндзя-разработчиков проекта ninjamock.com. Ninjamock.com [1] — это еще один онлайн-дизайнер скетчей и прототипов. Проект полностью написан на javascript и HTML5, серверная часть — на ASP.NET MVC.
За год работы над проектом мы наступили на огромное количество граблей и накопили бесценный опыт разработки больших приложений на JavaScript, которым и хотим поделиться. В этой статье мы расскажем, как прототип из одного файла index.html перерос в полноценный проект с более чем 250 классами и 60000 строк кода (не считая сторонних библиотек). Также, в общих чертах опишем нашу архитектуру и детально опишем реализацию отрисовки на клиенте.
Мы все работаем (всё еще работаем) в одной крупной компании, и как-то так совпало, что нам это надоело в один момент и мы решили захватить мир начать проект, который бы позволил нам работать на себя. Так, одним осенним днем мы собрались в баре выпить по кружке «чая» и обсудить, как это сделать. Где-то после N-й кружки наш гениальный план был готов:
Позже выяснилось, что мы не оригинальны и этот план придумали до нас — бизнес-план гномов [2].
Под скетч-дизайнером мы подразумеваем приложение, в котором можно рисовать скетчи, вайрфреймы или мокапы приложений, а также, делать простые кликабельные прототипы. Главная наша целевая аудитория — это программисты, дизайнеры, бизнес-аналитики и небольшие компании, занимающиеся разработкой мобильных приложений, которым нужно быстро нарисовать дизайн приложения, или же протестировать прототип.
Главным конкурентом мы считали хорошо известный balsamiq.com, чьи финансовые отчеты и вдохновили нас начать работать в этой области. Но, похоже, что мы были не одни, кто думал так же, и в течение года появилось несколько похожих проектов.
В отличие от balsamiq, который написан на flash, мы решили все делать «правильно» и писать на HTML5, чтобы можно было работать на всех платформах (и потому, что это был модный тренд на тот момент).
Еще одно наше отличие от balsamiq состоит в том, что мы ориентируемся на специфические платформы (iPhone, iPad, Windows Phone, и т.д.). То есть, бальзамик — это универсальная платформа для рисования чего угодно, поэтому у них нет семантики специфичной конкретным платформам. Зачем такая семантика нужна? Например, для генерации кода по нарисованному дизайну. У нас все контролы ведут себя более-менее как настоящие.
Серверная часть довольно проста и реализована на ASP.NET MVC; там, наверное, не о чем особо рассказывать. Большая часть кода у нас находится на клиенте и написана на JavaScript. Когда мы начинали проект, мы смотрели в сторону CoffeeScript, но посчитали, что инфраструктура для него на тот момент была достаточно сырой, так что мы решили писать все на чистом JavaScript.
Как и все уважающие себя JavaScript разработчики, мы изобрели не один велосипед и написали несколько своих фреймворков :) Например, у нас свой способ создания классов — там есть несколько интересных моментов, о которых мы расскажем в одной из следующих статей. Сейчас же, с появлением TypeScript, мы, скорее всего, перейдем на него, как только появится поддержка в WebStorm.
На клиенте у нас есть одна основная страница, на которой используется весь JavaScript. Из сторонних фреймворков, мы используем jQuery и knockout.js. Однако, архитектурно мы решили жестко не завязываться на сторонние фреймворки, поэтому у нас есть всего несколько платформо-зависимых классов, в которых разрешено их использование.
Код клиента включает в себя:
Но все начиналось гораздо проще…
Первый прототип был написан за несколько дней. В нем, как и должно быть в прототипе, все было очень просто. Наши контролы были HTML-элементами. Например, прямоугольник — это просто div, клавиатура телефона — это img, а элементы посложнее, там где нужны градиенты (например таб-бар или тулбар), — это canvas. Все элементы имели абсолютные координаты, положение элементов относительно друг друга задавалось через css-свойство z-index. Перемещение элементов было реализовано через jquery.draggable.
Все контролы размещались в div-элементе, который представлял собой нашу виртуальную страницу, т.е., он был шире и выше, чем рабочая область (для обеспечения скроллинга), а при масштабировании его размер соответствующим образом изменялся.
Главными плюсами такого подхода являются простота реализации и отличный скроллинг элементов, который браузер делает за нас, ну, и много других плюшек.
Такая архитектура просуществовала у нас несколько месяцев. Но наш проект рос и развивался, и, по мере добавления новых возможностей, мы поняли, что она нам не подходит.
Первым камнем преткновения стал банальный зум, который мы так и не смогли нормально реализовать. Собственно, у нас было два варианта:
Удивительно, но ни у одного из конкурирующих приложений, реализованных на HTML (fluidui.com, gomockingbird.com, moqups.com), нет масштабирования.
Нашим решением стало выбросить все HTML элементы и заменить их одним большим канвасом, на котором все и рисовалось. Размер канваса был равен размеру нашей виртуальной страницы. Поэтому скроллинг работал как и раньше но теперь появилась возможность все плавно масштабировать.
Дополнительным преимуществом такого подхода является легкий способ генерации картинки из канваса — это позволяет нам делать превьюшки страниц, используя метод canvas.toDataUrl. Причём, все это выполняется на клиенте и не нагружает сервер. Кроме этого, у нас появилась возможность обработки отдельных пикселов изображения (что в будущем позволит добавить интересные графические инструменты).
Рабочая область нашего приложения с 15-кратным масштабированием:
Однако и тут все оказалось не так просто. При любом перемещении элементов мышью (а это наиболее часто используемое действие), канвас со всеми контролами перерисовывался целиком, что значительно сказывалось на производительности приложения. Решилось это довольно просто — мы добавили еще один канвас поверх первого. Так у нас получилось 2 слоя (изначально их было 3 но это другая история :) ). Первый слой содержал более-менее статичную картинку, которая относительно редко перерисовывалась, в то время как на втором канвасе рисовались временные объекты и различные эффекты, такие как линии привязки и подсветка элементов при наведении. Результат удовлетворил нас почти полностью.
Однако, опять нашлись проблемы, которые показали несовершенство данного подхода. При масштабировании, размер изображения, а, соответственно, и размер канваса, увеличивался. По умолчанию, размер нашей дизайн-страницы равен 1024х768. При 4-кратном увеличении, размер канваса равен 4096х3072, и уже не каждая машина справляется с отрисовкой (с приемлемой скоростью). Более того, на нескольких машинах при таком увеличении стали появляться странные артефакты в виде полос и разноцветных точек. А ведь 4-кратное увеличение — это далеко не предел.
В результате, мы пришли к решению, которое и используем сейчас. Это все те же два канваса, но их размер теперь равен не размеру дизайн страницы, а размеру видимой части страницы на экране. Из-за этого нам пришлось отказаться от стандартного скроллинга и учитывать позицию скроллинга при отрисовке.
При таком подходе все работает отлично, за исключением одного небольшого минуса — скорость скроллинга незначительно упала по сравнению с предыдущими вариантами.
На скриншоте в начале статьи можно увидеть, как наш проект сейчас выглядит. Вживую его можно посмотреть здесь: ninjamock.com [1].
Сейчас мы активно работаем над увеличением количества контролов, поддерживаемых платформ (скоро появится пооддержка ipad, windows phone, surface, а так же десктоп приложений) и одновременно думаем над вторым пунктом нашего бизнес плана. Будем рады услышать любой фидбек и ответить на любые вопросы по нашему проекту.
Команда проекта ninjamock — pastorgluk [5], Денис и Headwithoutbrains [6].
Автор: HeadWithoutBrains
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/19916
Ссылки в тексте:
[1] Ninjamock.com: http://ninjamock.com
[2] бизнес-план гномов: http://ru.wikipedia.org/wiki/%D0%93%D0%BD%D0%BE%D0%BC%D1%8B_%28%D0%AE%D0%B6%D0%BD%D1%8B%D0%B9_%D0%BF%D0%B0%D1%80%D0%BA%29
[3] принцип открытости/закрытости: http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8/%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8
[4] jsfiddle.net/MzGpe/3/: http://jsfiddle.net/MzGpe/3/
[5] pastorgluk: http://habrahabr.ru/users/pastorgluk/
[6] Headwithoutbrains: http://habrahabr.ru/users/headwithoutbrains/
[7] Источник: http://habrahabr.ru/post/158383/
Нажмите здесь для печати.