Здравствуйте.
Мне бы хотелось рассказать про мой «Bart Chalkboard Generator».
Я уверен, что большинство из вас знают сериал «The Simpsons», и вы помните что почти в каждой новой заставке Барт писал на школьной доске что-то новое, типа: «They are laughing at me, not with me». А в интернете часто всплывает картинка с текстом: «I will use google before asking bump questions». И вот однажды я подумал, почему бы не создать простой генератор подобных картинок, да ещё и на Html5, что бы попрактиковаться?
Подготовка
Идея состояла в том что бы создать Canvas приложение которое бы отрисовывало заданный текст на шаблоне и давало возможность сохранить результат.
Я начал с создания спрайта в Фотошопе. За основу я взял картинку из интернета, разделил её на доску и на барта.
Схема отрисовки следующая:
- нарисовать доску
- нарисовать тектс
- нарисовать Барта поверх текста
Лирическое отступление
К моменту начала работы над этим мини-проектом я был знаком с js всего один день (я побывал на «Html5 games hackaton» от 2niversity.com). Я давно хотел начать изучать JS, но как-то не находилось идеи.
Html5 & Js
Код буду публиковать не полностью, ибо нет в этом смысла, исходники доступны.
Ну с Html все просто:
<canvas id='bart' width='500' height='310'></canvas>
В js я начал с определения некоторых переменных
var canvas = document.getElementById('bart'); //Определяю canvas
var ctx = canvas.getContext('2d'); //Определяю контехт canvas
var sprite = new Image();
sprite.src = 'images/sprite.png'; //Определяю спрайт
Дальше я создал основную функцию draw(text);
Которая задаёт функцию write(text,n,marginStep) и присвавает контексту (ctx) необходимые параметры
function draw(text){
marginTop = 36; //Определяю отступ сверху
line = ''; // Сбрасываю line
function write(text, n, marginStep){ // Эта функция напишет text по центру доски n раз с шагом по вертикали marginStep
for (var i = 0; i < n; i++) {
ctx.fillText(text, 250, marginTop);
marginTop += marginStep;
};
};
line = '';
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.font = '18px Flow';
Потом вычисляется длинна текста при заданных параметрах
textWidth = ctx.measureText(text).width;
Затем отрисовывается доска
ctx.drawImage(sprite, 0, 0, 500, 250, 0, 0, 500, 250);
После этого есть несколько вариантов развития событий. В зависимости от ширины введённого тескта скрипт настраивает размер шрифта оптимальным образом и рисует его в десять строк, или же, если текст совсем большой, рисует его по две строки 5 раз.
if (textWidth > 0 && textWidth <= 220){ //Вывод для 0-220 тескта (tc раз на строку)
textCount = Math.floor(450/(textWidth + 5)); // Узнаю сколько раз на строке поместится фраза( ширину холста делю на ширину(фразы+пробел))
for (var tc = 0; tc < textCount; tc++){ // Формирую строку
line += text + ' ';
};
line = line.slice(0, -1); // Убираю пробел в конце
write(line, 10, 20); //Пишу
}else if(textWidth > 220 && textWidth <= 225){ //Вывод для 221-225 текста (2 раза внутри строки)
ctx.font = '15px Flow'; //Уменьшаю шрифт
line = text + ' ' + text; //Формирую строку
write(line, 10, 20); //Пишу
}else if(textWidth > 225 && textWidth <= 360 ){ //Вывод для 226-360 текста (1 раз на строку)
ctx.font = '20px Flow'; //Увеличиваю шрифт
if (textWidth > 445){ //Проверяю не стал ли текст шире чем нужно, если так, то уменьшаю шрифт до стандартного
ctx.font = '18px Flow';
textWidth = ctx.measureText(text).width;
};
write(text, 10, 20); //Пишу
}else if(textWidth > 360 && textWidth <= 450 ){ //Вывод для 361-450 текста, самый простой (1 раз на строку стандартным шрифтом)
write(text, 10, 20); //Соответственно сразу пишу
}else if(textWidth > 450 && textWidth <= 500){ //Вывод 451-500 текста (1 раз на строку)
ctx.font = '15px Flow'; //Уменьшаю шрифт
write(text, 10, 20);
}
Дальше идёт вывод двухстрочного текста который я взял у naxel, здесь, спасибо ему за это.
Способ состоит в том, что текст сначала разбивается по словам в массив words, потом склеивается обратно по одному слову с пробелом и после каждой склейки проверяется ширина получившейся строки.
Если ширина больше 450(ширина доски), то в canvas выводится эта строчка без последнего добавленного слова 5 раз с отступом 40. Далее просто доклеивается вторая строчка и так же выводится 5 раз.
else if(textWidth > 500 && textWidth <= 700){ //Вывод 501-700 текста 2строчный!
var words = text.split(' '); //Разбиваю текст на слова и зпихиваю их в массив words
var countWords = words.length; //Считаю количество слов
if(countWords > 4){
for (var n = 0; n < countWords; n++) { //Этот цикл будет вращатся countWords раз и в результате отдаст на доску 1 строчку, а в line положит вторую
var testLine = line + words[n] + ' '; //Создаю тестовую строку
var testWidth = ctx.measureText(testLine).width;//Узнаю и проверяю её ширину
if (testWidth > 450) { //Если ширина тестовой строки уже больше чем доска
write(line, 5, 40); //Пишу 5 раз с шагом 40 (через строчку) начиная с 36
line = words[n] + ' '; //Сбрасываю line до последнего перебранного слова
}else {
line = testLine;
};
};
marginTop = 56; //Устанавливаю отступ на 2 строчку
write(line, 5, 40); //Пишу вторую строчку фразы 5 раз с шагом 40(через строчку) начиная со второй строки доски
}
В конце рисуется Барт.
ctx.drawImage(sprite, 498, 128, 80, 180, 406, 118, 80, 180); //Рисую Барта повер всего этого безобразия
Вот собственно и всё, остается прикрутить текстовую форму и кнопку.
Html
<form name='form_1' onsubmit='return false;' id='form_1'>
<input name='inputText' id='inputText' type='text' maxlength='150' autocomplete='off' autofocus placeholder='Напиши сюда что-нибудь, скорее!'>
<input id='writeIt' type='button' value='Написать!'>
<input id='downloadIt' type='button' class='center' value='Скачать!' >
</form>
Js
document.getElementById('writeIt').onclick=function(e){draw(document.forms.form_1.elements.inputText.value)};
document.getElementById('form_1').onsubmit=function(e){ //Нажатие Enter
draw(document.forms.form_1.elements.inputText.value);
return false //Отменяю действие браузера
};
Сохранение картинки
Для сохранения картинки я воспользовался toDataURL('image/png'). Просто открываю новое окно с url canvas.toDataURL('image/png')
document.getElementById('downloadIt').onclick=function(e){
ctx.drawImage(sprite, 9, 250, 142, 25, 17, 222, 142, 25); //Рисую копирайт
window.open(canvas.toDataURL("image/png"), "Скачать Bart's Chalkoard", "resizable=no,toolbar=no,menubar=no,location=no,scrollbars=no,status=no,width=530,height=340, left=400, top=120,"); //Задаю параметры всплывающего окна.
ctx.drawImage(sprite, 16, 226, 134, 18, 16, 226, 134, 18); //Затираю копирайт кусочком доски
};
Заключение
На всё это у меня ушло примерно две ночи и да дня, знаю что для нормального программиста это очень долго, но я только начал учить js, так что я собой почти доволен.
Извинения и оправдания.
Извините, если в коде есть какие промахи или недочёты. Я правда старался всё сделать красиво и правильно.
Извините, если что-то не так в оформление поста, опять же это мой первый пост, я старался.
Демо
Опробовать можно сдесь bart.grindel.su, исходники там же.
Грузится не очень быстро т.к. размещено на моём домашнем сервере который выходит в интернет через очень странный роутер, так что придётся подождать.
Источники
- habrahabr.ru/post/119772/ Canvas F.A.Q
- htmlbook.ru/html5 о Html5
- javascript.ru сайт о js
- javascript.ru/forum форум на котором мне помогал очень добрый и терпеливы человек с ником vadim5june, спасибо ему за это!
- html5canvastutorials.com отличные уроки по canvas
- Остальное по мелочи в Google
Надеюсь кому-нибудь было интересно это прочитать.
Спасибо за внимание!
Автор: grindel