SlideShare a Scribd company logo
1 of 68
Редактор Mail.ru
Александр Русаков, Ведущий программист
Редактор
• Просмотр документов
• Превью документов
• Редактирование документов
Задачи
• Просмотр документов
• Превью документов
Как решить задачу «в лоб»?
Этапы обработки документа
Получение модели
документа от сервера
Расчёт документа
Генерация HTML
Модель
{
"sections": [{
"elements": [{
"type": "paragraph",
"elements": [{
"type": "text",
"text": "Testn",
"font": {
"bold": true
}
}],...
Не подходит для редактирования:
• Нельзя разделить на части
• Нет простого механизма адресации по
вложенной структуре
Модель. Минусы
Модель. Адресация
{
"sections": [{
"elements": [{
"type": "paragraph",
"elements": [{
"type": "text",
"text": "Testn",
"font": {
"bold": true
}
}],...
Как адресовать символ?
Этапы обработки документа
Получение модели
документа от сервера
Расчёт документа
Генерация HTML
Заливка у слов разной высоты
Картинки «вокруг рамки»
Расчет документа. Зачем?
Браузер width
Chrome 38 285.53…
Firefox 33 283.17…
IE 11 286
Opera 12.16 280
Расчет документа. Получение размера
ctx.font = '28pt Arial';
ctx.measureText('Редактор Mail.ru');
Размеры слов и букв различаются между браузерами
Документ в разных браузерах
рассчитывается по разному
Расчет документа. Минусы
Firefox IE11
Этапы обработки документа
Получение модели
документа от сервера
Расчёт документа
Генерация HTML
HTML
• Отображение текста различается между
браузерами
• Низкая скорость манипуляций с DOM
HTML. Минусы
Исполняем js-код на сервере
НО PhantomJS:
• Медленный
• Нестабильный
Превью. PhantomJS
Формулировка проблем
Использовали Проблема
Модель вложенная Нельзя разделить на части
Сложный механизм адресации
Размер шрифта вычисляется в
браузере
Разный размер букв и слов в
разных браузерах
HTML Разное отображение текста
Медленные манипуляции с DOM
PhantomJS Медленный
Нестабильный
Отказываемся от получения модели от сервера.
От сервера принимаем набор команд.
Модель вложенная. Как разделить на части?
Команды – низкоуровневые операции, изменяющие документ.
Например:
• TextInsert (start : number, text : string)
• TextDelete (start : number, end : number)
• ParagraphUpdate (end : number, props: Object)
• …
Команды
Команды. Пример
TextInsert(0,'П')
TextInsert(1,'р')
TextInsert(2,'у')
TextInsert(3,'д')
Команды. Пример
TextDelete(0, 1)
TextInsert(0,'Т')
Приходят с сервера
Создаются на клиенте на каждое действие пользователя:
• Ввод текста
• Изменение свойств (шрифт, цвет и т.д.)
Команды. Откуда?
Отправляются на сервер:
• По таймауту (автосохранение)
• По нажатию кнопки «Сохранить»
Команды. Куда?
Модель вложенная. Как адресовать символ?
Модель вложенная
Параграф Таблица
Текст ЯчейкаТекст Ячейка
ТаблицаПараграф
ЯчейкаТекст
Новая плоская модель
Модель плоская
Параграф 1 Параграф N
Текст
Таблица 1 Таблица M
Ячейка 1 Ячейка L
Команды формируют модель
{
"text": "Hello, world!n
}
TextInsert(0,'Hello, world!n')
Команды формируют модель на клиенте
RunUpdate(0, 4, {
bold: true
})
{
"text": "Hello, world!n",
"runs": [{
"start": 0,
"end": 4,
"bold": true
}]
}
Команды формируют модель на клиенте
{
"text": "Hello, world!n",
"runs": [{
"start": 0,
"end": 4,
"bold": true
}],
"paragraphs": [{
"end": 13
}]
}
Paragraph(13)
Модель. «Плоская»
{
"text": "Hello, world!n",
"runs": [{
"start": 0,
"end": 4,
"bold": true
}],
"paragraphs": [{
"end": 13
}]
}
Свойство text – весь текст
документа.
Адресация по индексу
строки text.
Каждый браузер измеряет по-своему
Расчет документа. Разные размеры букв
Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
Расчет документа. Разные размеры букв
Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
В HTML нельзя указать размер слова по ширине
Расчет документа. Разные размеры букв
Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
В HTML нельзя указать размер слова по ширине
Решение. Canvas может принудительно уместить слово
по ширине
Расчет документа. Разные размеры букв
Шрифтов много хороших и разных…
Какие шрифты нужны?
Расчет документа. Шрифты
Расчет документа. Статистика по шрифтам
Times New Roman Calibri
Tahoma Arial
Courier New Symbol
Wingdings Cambria
Verdana
Расчет документа. Размеры шрифта
{
"widths": {
"a": 1139, ...
},
"ascent": 1921,
"descent": -434,
"factor": 2048
}
C сервера приходят JSON c рассчитанными размерами шрифта
Расчет размеров букв теперь не зависят от браузера!
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
Расчет документа. Слова
Простое слово
Пробельное слово
Табуляция
Разрыв страницы
Перенос строки
Расчет документа. Процесс
Слово большее по высоте сдвигает строку вниз
Расчет документа. Процесс
Если слово длиннее строки, то слово разделяется на две части
Расчет документа. Что-то посложнее
Как рассчитать подобное?
Картинка имеет обтекание текстом – «вокруг рамки»
Расчет документа. Что-то посложнее
Сначала располагаем картинку относительно
левого верхнего угла параграфа
Расчет документа. Что-то посложнее
Пытаем получить прямоугольник для строки – пересечение!
Расчет документа. Что-то посложнее
Строка разбивается на несколько допустимых участков
Расчет документа. Что-то посложнее
Размещаем слова по допустимым участкам
Расчет документа. Что-то посложнее
Итак весь параграф
4 аргумент – максимальная ширина текста
Canvas
ctx.fillText(text, x, y, maxWidth);
Canvas может принудительно уместить слово в
заданный размер
• Полный контроль над расположением элементов и их размерами
• Простая логика на уровне View
• Производительность (client side and server side)
• Используем node.js + node-canvas вместо phantomjs
• C согласия пользователя к репорту прикрепляется скриншот
документа
Canvas. Плюсы
Нет DOM:
• Самостоятельная обработка событий пользователя
• Нельзя заменить содержимое тега, поменять стиль => только
перерисовать
Canvas. Минусы
Используем два <canvas> на странице
Canvas. Больше одного на странице
Один – для текста, второй – для выделения и курсора
ctx.fillRect() должен работать с целыми числами, нужно округлять
Canvas. Округление и целые числа
ctx.fillRect(
round(x),
round(y),
round(w),
round(h)
);
Canvas. Округление и целые числа
y = 10.5;
h = 4.7;
round(y) === 11;
round(h) === 5;
Canvas. Округление и целые числа
y = 10.5;
h = 4.7;
round(y) === 11;
round(h) === 5;
round(y) === 11;
round(y + h) - round(y) === 4;
Заливка находится под текстом, но перед фоном страницы
Строка может вылезать за пределы страницы – нужно обрезать
Canvas. Заливка и обрезка
Рисуем фон под текстом (текст + фон за один проход)
Canvas. Off-screen canvas
ctx.globalCompositeOperation = 'destination-over';
Копируем off-screen canvas в основной с помощью drawImage
var offSreenCanvas = document.createElement('canvas');
ctx.drawImage(offSreenCanvas, ...);
Canvas. Превью и печать
Модуль node-canvas – Canvas API для Node.js
Дает возможность генерировать PDF (печать!)
ctx.addPage(width, height);
Canvas. PDF, первый подход
Использование Off-screen canvas растеризовало текст
Отказываемся от off-sreen canvas в пользу метода clip() для обрезки
ctx.save();
ctx.rect(x, y, w, h);
ctx.clip();
// render
ctx.restore();
Canvas. Почему все стало тормозить?!
save() / restore() действительно сбрасывают clip()
Но:
clip() оперирует путем (path)
Путь всегда один
Путь не сбрасывается во время restore()
Canvas. Правильное использование clip()
ctx.save();
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.clip();
// render
ctx.restore();
Тень вокруг листа.
В превью не нужна тень!
Убрали тень в генерации
превью (Node.js) – время
снизилось в среднем на
50мс
Canvas. Ускоряем превью
Canvas. Дисплеи retina и devicePixelRatio
ctx.scale(devicePixelRatio, devicePixelRatio);
<canvas width="1486" height="434" style="height: 347px; width:1189px;">
</canvas>
Увеличиваем размер Canvas в devicePixeRatio раз и
сжимаем обратно с помощью CSS
В отрисовке увеличиваем масштаб
Результат
Было Стало
Отображение в разных
браузерах
Разное Идентичное
Генерация превью PhantomJS – 600 мс Node.js – 350 мс
Печать Средствами
браузера
Генерация PDF для
печати на сервере
СПАСИБО
ЗА ВНИМАНИЕ
a.rusakov@corp.mail.ru
Инструмент Функции
git + phabricator + arcanist Управление и review кода
Grunt Сборка проекта
SASS + autoprefixer Работаем c css
Karma+PhantomJS, instabul Запуск тестов, code coverage
Что мы используем?
Библиотека Функции
Requirejs AMD модули
jQuery Обработка событий + AJAX
Mail.ru FileAPI Загрузка картинок на сервер
Jasmine Unit тесты
Node-canvas Серверная реализация Canvas API
Что мы используем?

More Related Content

Similar to Редактор Mail.ru. Frontend

CSS глазами машин
CSS глазами машинCSS глазами машин
CSS глазами машинRoman Dvornov
 
самоучитель по креативному Web дизайну
самоучитель по креативному Web дизайнусамоучитель по креативному Web дизайну
самоучитель по креативному Web дизайнуStAlKeRoV
 
Web весна 2013 лекция 10
Web весна 2013 лекция 10Web весна 2013 лекция 10
Web весна 2013 лекция 10Technopark
 
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18OdessaFrontend
 
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETОпыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETGoSharp
 
Верстка_Лекция_3
Верстка_Лекция_3Верстка_Лекция_3
Верстка_Лекция_3itc73
 
колесников Rit 16x9
колесников Rit 16x9колесников Rit 16x9
колесников Rit 16x9rit2010
 
Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)Ontico
 
сысоев андрей
сысоев андрейсысоев андрей
сысоев андрейVlado Sudin
 
сысоев андрей
сысоев андрейсысоев андрей
сысоев андрейVlado Sudin
 
«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...
«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...
«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...Анастасия Вязьмина
 
Web осень 2012 лекция 10
Web осень 2012 лекция 10Web осень 2012 лекция 10
Web осень 2012 лекция 10Technopark
 
модуль 1. основы работы в illustrator 1. введение
модуль 1. основы работы в illustrator 1. введениемодуль 1. основы работы в illustrator 1. введение
модуль 1. основы работы в illustrator 1. введениеEd Solovey
 
High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9HighLoad2009
 
Программируем быстрее с CodeRush
Программируем быстрее с CodeRushПрограммируем быстрее с CodeRush
Программируем быстрее с CodeRushgeekfamilyrussia
 
Present forms&css
Present forms&cssPresent forms&css
Present forms&cssitc73
 
Вебинар "Оптимизация производительности мобильных веб-приложений"
Вебинар "Оптимизация производительности мобильных веб-приложений"Вебинар "Оптимизация производительности мобильных веб-приложений"
Вебинар "Оптимизация производительности мобильных веб-приложений"MobiDev
 

Similar to Редактор Mail.ru. Frontend (20)

CSS глазами машин
CSS глазами машинCSS глазами машин
CSS глазами машин
 
самоучитель по креативному Web дизайну
самоучитель по креативному Web дизайнусамоучитель по креативному Web дизайну
самоучитель по креативному Web дизайну
 
Web весна 2013 лекция 10
Web весна 2013 лекция 10Web весна 2013 лекция 10
Web весна 2013 лекция 10
 
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
 
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETОпыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
 
Верстка_Лекция_3
Верстка_Лекция_3Верстка_Лекция_3
Верстка_Лекция_3
 
колесников Rit 16x9
колесников Rit 16x9колесников Rit 16x9
колесников Rit 16x9
 
Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)
 
сысоев андрей
сысоев андрейсысоев андрей
сысоев андрей
 
сысоев андрей
сысоев андрейсысоев андрей
сысоев андрей
 
«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...
«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...
«Облачный» сервис интеллектуального анализа данных. графический интерфейс пос...
 
Web осень 2012 лекция 10
Web осень 2012 лекция 10Web осень 2012 лекция 10
Web осень 2012 лекция 10
 
модуль 1. основы работы в illustrator 1. введение
модуль 1. основы работы в illustrator 1. введениемодуль 1. основы работы в illustrator 1. введение
модуль 1. основы работы в illustrator 1. введение
 
High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9
 
Программируем быстрее с CodeRush
Программируем быстрее с CodeRushПрограммируем быстрее с CodeRush
Программируем быстрее с CodeRush
 
Present forms&css
Present forms&cssPresent forms&css
Present forms&css
 
Вебинар "Оптимизация производительности мобильных веб-приложений"
Вебинар "Оптимизация производительности мобильных веб-приложений"Вебинар "Оптимизация производительности мобильных веб-приложений"
Вебинар "Оптимизация производительности мобильных веб-приложений"
 
Batch processing on RoR
Batch processing on RoRBatch processing on RoR
Batch processing on RoR
 
Svg
SvgSvg
Svg
 
Clojure #2 (2014)
Clojure #2 (2014)Clojure #2 (2014)
Clojure #2 (2014)
 

Редактор Mail.ru. Frontend

Editor's Notes

  1. http://jsfiddle.net/yqkmzzam/6/
  2. Заменить картинку
  3. Диаграмма классов
  4. Диаграмма классов
  5. Диаграмма классов
  6. Диаграмма классов