Редактор mail.ru. frontend
TRANSCRIPT
![Page 1: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/1.jpg)
Редактор Mail.ru
Александр Русаков, Ведущий программист
![Page 2: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/2.jpg)
Редактор
![Page 3: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/3.jpg)
• Просмотр документов
• Превью документов
• Редактирование документов
Задачи
![Page 4: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/4.jpg)
• Просмотр документов
• Превью документов
Как решить задачу «в лоб»?
![Page 5: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/5.jpg)
Этапы обработки документа
Получение модели
документа от сервера
Расчёт документа
Генерация HTML
![Page 6: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/6.jpg)
Модель
{
"sections": [{
"elements": [{
"type": "paragraph",
"elements": [{
"type": "text",
"text": "Test\n",
"font": {
"bold": true
}
}],...
![Page 7: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/7.jpg)
Не подходит для редактирования:
• Нельзя разделить на части
• Нет простого механизма адресации по
вложенной структуре
Модель. Минусы
![Page 8: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/8.jpg)
Модель. Адресация
{
"sections": [{
"elements": [{
"type": "paragraph",
"elements": [{
"type": "text",
"text": "Test \n",
"font": {
"bold": true
}
}],...
Как адресовать символ?
![Page 9: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/9.jpg)
Этапы обработки документа
Получение модели
документа от сервера
Расчёт документа
Генерация HTML
![Page 10: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/10.jpg)
Заливка у слов разной высоты
Картинки «вокруг рамки»
Расчет документа. Зачем?
![Page 11: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/11.jpg)
Браузер width
Chrome 38 285.53…
Firefox 33 283.17…
IE 11 286
Opera 12.16 280
Расчет документа. Получение размера
ctx.font = '28pt Arial';
ctx.measureText('Редактор Mail.ru');
Размеры слов и букв различаются между браузерами
![Page 12: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/12.jpg)
Документ в разных браузерах
рассчитывается по разному
Расчет документа. Минусы
Firefox IE11
![Page 13: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/13.jpg)
Этапы обработки документа
Получение модели
документа от сервера
Расчёт документа
Генерация HTML
![Page 14: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/14.jpg)
HTML
![Page 15: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/15.jpg)
• Отображение текста различается между
браузерами
• Низкая скорость манипуляций с DOM
HTML. Минусы
![Page 16: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/16.jpg)
Исполняем js-код на сервере
НО PhantomJS:
• Медленный
• Нестабильный
Превью. PhantomJS
![Page 17: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/17.jpg)
Формулировка проблем
Использовали Проблема
Модель вложенная Нельзя разделить на части
Сложный механизм адресации
Размер шрифта вычисляется в
браузере
Разный размер букв и слов в
разных браузерах
HTML Разное отображение текста
Медленные манипуляции с DOM
PhantomJS Медленный
Нестабильный
![Page 18: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/18.jpg)
Отказываемся от получения модели от сервера.
От сервера принимаем набор команд.
Модель вложенная. Как разделить на части?
![Page 19: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/19.jpg)
Команды – низкоуровневые операции, изменяющие документ.
Например:
• TextInsert (start : number, text : string)
• TextDelete (start : number, end : number)
• ParagraphUpdate (end : number, props: Object)
• …
Команды
![Page 20: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/20.jpg)
Команды. Пример
TextInsert(0,'П')
TextInsert(1,'р')
TextInsert(2,'у')
TextInsert(3,'д')
![Page 21: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/21.jpg)
Команды. Пример
TextDelete(0, 1)
TextInsert(0,'Т')
![Page 22: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/22.jpg)
Приходят с сервера
Создаются на клиенте на каждое действие пользователя:
• Ввод текста
• Изменение свойств (шрифт, цвет и т.д.)
Команды. Откуда?
![Page 23: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/23.jpg)
Отправляются на сервер:
• По таймауту (автосохранение)
• По нажатию кнопки «Сохранить»
Команды. Куда?
![Page 24: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/24.jpg)
Модель вложенная. Как адресовать символ?
Модель вложенная
Параграф Таблица
Текст ЯчейкаТекст Ячейка
ТаблицаПараграф
ЯчейкаТекст
![Page 25: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/25.jpg)
Новая плоская модель
Модель плоская
Параграф 1 Параграф N
Текст
Таблица 1 Таблица M
Ячейка 1 Ячейка L
![Page 26: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/26.jpg)
Команды формируют модель
{
"text": "Hello, world!\n
}
TextInsert(0,'Hello, world!\n')
![Page 27: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/27.jpg)
Команды формируют модель на клиенте
RunUpdate(0, 4, {
bold: true
})
{
"text": "Hello, world!\n",
"runs": [{
"start": 0,
"end": 4,
"bold": true
}]
}
![Page 28: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/28.jpg)
Команды формируют модель на клиенте
{
"text": "Hello, world!\n",
"runs": [{
"start": 0,
"end": 4,
"bold": true
}],
"paragraphs": [{
"end": 13
}]
}
Paragraph(13)
![Page 29: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/29.jpg)
Модель. «Плоская»
{
"text": "Hello, world!\n",
"runs": [{
"start": 0,
"end": 4,
"bold": true
}],
"paragraphs": [{
"end": 13
}]
}
Свойство text – весь текст
документа.
Адресация по индексу
строки text.
![Page 30: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/30.jpg)
Каждый браузер измеряет по-своему
Расчет документа. Разные размеры букв
![Page 31: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/31.jpg)
Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
Расчет документа. Разные размеры букв
![Page 32: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/32.jpg)
Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
В HTML нельзя указать размер слова по ширине
Расчет документа. Разные размеры букв
![Page 33: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/33.jpg)
Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
В HTML нельзя указать размер слова по ширине
Решение. Canvas может принудительно уместить слово
по ширине
Расчет документа. Разные размеры букв
![Page 34: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/34.jpg)
Шрифтов много хороших и разных…
Какие шрифты нужны?
Расчет документа. Шрифты
![Page 35: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/35.jpg)
Расчет документа. Статистика по шрифтам
Times New Roman Calibri
Tahoma Arial
Courier New Symbol
Wingdings Cambria
Verdana
![Page 36: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/36.jpg)
Расчет документа. Размеры шрифта
{
"widths": {
"a": 1139, ...
},
"ascent": 1921,
"descent": -434,
"factor": 2048
}
C сервера приходят JSON c рассчитанными размерами шрифта
Расчет размеров букв теперь не зависят от браузера!
![Page 37: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/37.jpg)
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
![Page 38: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/38.jpg)
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
![Page 39: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/39.jpg)
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
![Page 40: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/40.jpg)
Расчет документа. Итоговая структура
Документ
Секция
Страница
Строка
Слово
![Page 41: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/41.jpg)
Расчет документа. Слова
Простое слово
Пробельное слово
Табуляция
Разрыв страницы
Перенос строки
![Page 42: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/42.jpg)
Расчет документа. Процесс
Слово большее по высоте сдвигает строку вниз
![Page 43: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/43.jpg)
Расчет документа. Процесс
Если слово длиннее строки, то слово разделяется на две части
![Page 44: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/44.jpg)
Расчет документа. Что-то посложнее
Как рассчитать подобное?
Картинка имеет обтекание текстом – «вокруг рамки»
![Page 45: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/45.jpg)
Расчет документа. Что-то посложнее
Сначала располагаем картинку относительно
левого верхнего угла параграфа
![Page 46: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/46.jpg)
Расчет документа. Что-то посложнее
Пытаем получить прямоугольник для строки – пересечение!
![Page 47: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/47.jpg)
Расчет документа. Что-то посложнее
Строка разбивается на несколько допустимых участков
![Page 48: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/48.jpg)
Расчет документа. Что-то посложнее
Размещаем слова по допустимым участкам
![Page 49: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/49.jpg)
Расчет документа. Что-то посложнее
Итак весь параграф
![Page 50: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/50.jpg)
4 аргумент – максимальная ширина текста
Canvas
ctx.fillText(text, x, y, maxWidth);
Canvas может принудительно уместить слово в
заданный размер
![Page 51: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/51.jpg)
• Полный контроль над расположением элементов и их размерами
• Простая логика на уровне View
• Производительность (client side and server side)
• Используем node.js + node-canvas вместо phantomjs
• C согласия пользователя к репорту прикрепляется скриншот
документа
Canvas. Плюсы
![Page 52: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/52.jpg)
Нет DOM:
• Самостоятельная обработка событий пользователя
• Нельзя заменить содержимое тега, поменять стиль => только
перерисовать
Canvas. Минусы
![Page 53: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/53.jpg)
Используем два <canvas> на странице
Canvas. Больше одного на странице
Один – для текста, второй – для выделения и курсора
![Page 54: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/54.jpg)
ctx.fillRect() должен работать с целыми числами, нужно округлять
Canvas. Округление и целые числа
ctx.fillRect(
round(x),
round(y),
round(w),
round(h)
);
![Page 55: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/55.jpg)
Canvas. Округление и целые числа
y = 10.5;
h = 4.7;
round(y) === 11;
round(h) === 5;
![Page 56: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/56.jpg)
Canvas. Округление и целые числа
y = 10.5;
h = 4.7;
round(y) === 11;
round(h) === 5;
round(y) === 11;
round(y + h) - round(y) === 4;
![Page 57: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/57.jpg)
Заливка находится под текстом, но перед фоном страницы
Строка может вылезать за пределы страницы – нужно обрезать
Canvas. Заливка и обрезка
![Page 58: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/58.jpg)
Рисуем фон под текстом (текст + фон за один проход)
Canvas. Off-screen canvas
ctx.globalCompositeOperation = 'destination-over';
Копируем off-screen canvas в основной с помощью drawImage
var offSreenCanvas = document.createElement('canvas');
ctx.drawImage(offSreenCanvas, ...);
![Page 59: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/59.jpg)
Canvas. Превью и печать
Модуль node-canvas – Canvas API для Node.js
Дает возможность генерировать PDF (печать!)
ctx.addPage(width, height);
![Page 60: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/60.jpg)
Canvas. PDF, первый подход
Использование Off-screen canvas растеризовало текст
Отказываемся от off-sreen canvas в пользу метода clip() для обрезки
ctx.save();
ctx.rect(x, y, w, h);
ctx.clip();
// render
ctx.restore();
![Page 61: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/61.jpg)
Canvas. Почему все стало тормозить?!
save() / restore() действительно сбрасывают clip()
Но:clip() оперирует путем (path)
Путь всегда один
Путь не сбрасывается во время restore()
![Page 62: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/62.jpg)
Canvas. Правильное использование clip()
ctx.save();
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.clip();
// render
ctx.restore();
![Page 63: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/63.jpg)
Тень вокруг листа.
В превью не нужна тень!
Убрали тень в генерации
превью (Node.js) – время
снизилось в среднем на
50мс
Canvas. Ускоряем превью
![Page 64: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/64.jpg)
Canvas. Дисплеи retina и devicePixelRatio
ctx.scale(devicePixelRatio, devicePixelRatio);
<canvas width="1486" height="434" style="height: 347px; width:1189px;">
</canvas>
Увеличиваем размер Canvas в devicePixeRatio раз и
сжимаем обратно с помощью CSS
В отрисовке увеличиваем масштаб
![Page 65: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/65.jpg)
Результат
Было Стало
Отображение в разных
браузерах
Разное Идентичное
Генерация превью PhantomJS – 600 мс Node.js – 350 мс
Печать Средствами
браузера
Генерация PDF для
печати на сервере
![Page 67: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/67.jpg)
Инструмент Функции
git + phabricator + arcanist Управление и review кода
Grunt Сборка проекта
SASS + autoprefixer Работаем c css
Karma+PhantomJS, instabul Запуск тестов, code coverage
Что мы используем?
![Page 68: Редактор Mail.ru. Frontend](https://reader034.vdocuments.net/reader034/viewer/2022042518/55abe1cb1a28abcc1f8b4582/html5/thumbnails/68.jpg)
Библиотека Функции
Requirejs AMD модули
jQuery Обработка событий + AJAX
Mail.ru FileAPI Загрузка картинок на сервер
Jasmine Unit тесты
Node-canvas Серверная реализация Canvas API
Что мы используем?