Bart Chalkboard Generator

Здравствуйте.
Мне бы хотелось рассказать про мой «Bart Chalkboard Generator».



Я уверен, что большинство из вас знают сериал «The Simpsons», и вы помните что почти в каждой новой заставке Барт писал на школьной доске что-то новое, типа: «They are laughing at me, not with me». А в интернете часто всплывает картинка с текстом: «I will use google before asking dump 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);
    }

Способ состоит в том, что текст сначала разбивается по словам в массив 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); //Рисую Барта повер всего этого безобразия

Вот собственно и всё, остается прикрутить текстовую форму и кнопку.
<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>

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, так что я собой почти доволен.

Извинения и оправдания.

Извините, если в коде есть какие промахи или недочёты. Я правда старался всё сделать красиво и правильно.
Извините, если что-то не так в оформление поста, опять же это мой первый пост, я старался.
Теги:
textWidth, write, sprite, canvas, текста, Вывод, document, words, текст, строки, width, function, countWords, строку, drawImage, value, Определяю, getElementById, ширина, строчку, marginTop, inputText, Html5, шрифт , Пишу , нарисовать, marginStep, шагом, measureText, начал, строку , testLine, image, toDataURL, input
Добавлено: 11 Сентября 2013 02:03:39 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...