15. • Отображение текста различается между
браузерами
• Низкая скорость манипуляций с DOM
HTML. Минусы
16. Исполняем js-код на сервере
НО PhantomJS:
• Медленный
• Нестабильный
Превью. PhantomJS
17. Формулировка проблем
Использовали Проблема
Модель вложенная Нельзя разделить на части
Сложный механизм адресации
Размер шрифта вычисляется в
браузере
Разный размер букв и слов в
разных браузерах
HTML Разное отображение текста
Медленные манипуляции с DOM
PhantomJS Медленный
Нестабильный
18. Отказываемся от получения модели от сервера.
От сервера принимаем набор команд.
Модель вложенная. Как разделить на части?
19. Команды – низкоуровневые операции, изменяющие документ.
Например:
• TextInsert (start : number, text : string)
• TextDelete (start : number, end : number)
• ParagraphUpdate (end : number, props: Object)
• …
Команды
31. Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
Расчет документа. Разные размеры букв
32. Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
В HTML нельзя указать размер слова по ширине
Расчет документа. Разные размеры букв
33. Каждый браузер измеряет по-своему
Решение. Присылаем размеры шрифта с сервера
В HTML нельзя указать размер слова по ширине
Решение. Canvas может принудительно уместить слово
по ширине
Расчет документа. Разные размеры букв
35. Расчет документа. Статистика по шрифтам
Times New Roman Calibri
Tahoma Arial
Courier New Symbol
Wingdings Cambria
Verdana
36. Расчет документа. Размеры шрифта
{
"widths": {
"a": 1139, ...
},
"ascent": 1921,
"descent": -434,
"factor": 2048
}
C сервера приходят JSON c рассчитанными размерами шрифта
Расчет размеров букв теперь не зависят от браузера!
50. 4 аргумент – максимальная ширина текста
Canvas
ctx.fillText(text, x, y, maxWidth);
Canvas может принудительно уместить слово в
заданный размер
51. • Полный контроль над расположением элементов и их размерами
• Простая логика на уровне View
• Производительность (client side and server side)
• Используем node.js + node-canvas вместо phantomjs
• C согласия пользователя к репорту прикрепляется скриншот
документа
Canvas. Плюсы
52. Нет DOM:
• Самостоятельная обработка событий пользователя
• Нельзя заменить содержимое тега, поменять стиль => только
перерисовать
Canvas. Минусы
53. Используем два <canvas> на странице
Canvas. Больше одного на странице
Один – для текста, второй – для выделения и курсора
54. ctx.fillRect() должен работать с целыми числами, нужно округлять
Canvas. Округление и целые числа
ctx.fillRect(
round(x),
round(y),
round(w),
round(h)
);
55. Canvas. Округление и целые числа
y = 10.5;
h = 4.7;
round(y) === 11;
round(h) === 5;
56. Canvas. Округление и целые числа
y = 10.5;
h = 4.7;
round(y) === 11;
round(h) === 5;
round(y) === 11;
round(y + h) - round(y) === 4;
57. Заливка находится под текстом, но перед фоном страницы
Строка может вылезать за пределы страницы – нужно обрезать
Canvas. Заливка и обрезка
58. Рисуем фон под текстом (текст + фон за один проход)
Canvas. Off-screen canvas
ctx.globalCompositeOperation = 'destination-over';
Копируем off-screen canvas в основной с помощью drawImage
var offSreenCanvas = document.createElement('canvas');
ctx.drawImage(offSreenCanvas, ...);
59. Canvas. Превью и печать
Модуль node-canvas – Canvas API для Node.js
Дает возможность генерировать PDF (печать!)
ctx.addPage(width, height);
60. Canvas. PDF, первый подход
Использование Off-screen canvas растеризовало текст
Отказываемся от off-sreen canvas в пользу метода clip() для обрезки
ctx.save();
ctx.rect(x, y, w, h);
ctx.clip();
// render
ctx.restore();
61. Canvas. Почему все стало тормозить?!
save() / restore() действительно сбрасывают clip()
Но:
clip() оперирует путем (path)
Путь всегда один
Путь не сбрасывается во время restore()
63. Тень вокруг листа.
В превью не нужна тень!
Убрали тень в генерации
превью (Node.js) – время
снизилось в среднем на
50мс
Canvas. Ускоряем превью
64. Canvas. Дисплеи retina и devicePixelRatio
ctx.scale(devicePixelRatio, devicePixelRatio);
<canvas width="1486" height="434" style="height: 347px; width:1189px;">
</canvas>
Увеличиваем размер Canvas в devicePixeRatio раз и
сжимаем обратно с помощью CSS
В отрисовке увеличиваем масштаб
65. Результат
Было Стало
Отображение в разных
браузерах
Разное Идентичное
Генерация превью PhantomJS – 600 мс Node.js – 350 мс
Печать Средствами
браузера
Генерация PDF для
печати на сервере
67. Инструмент Функции
git + phabricator + arcanist Управление и review кода
Grunt Сборка проекта
SASS + autoprefixer Работаем c css
Karma+PhantomJS, instabul Запуск тестов, code coverage
Что мы используем?
68. Библиотека Функции
Requirejs AMD модули
jQuery Обработка событий + AJAX
Mail.ru FileAPI Загрузка картинок на сервер
Jasmine Unit тесты
Node-canvas Серверная реализация Canvas API
Что мы используем?