Веб-программирование

Создаем интерактивные типографские эффекты

HTML5 набирает популярность и этот урок описывает то, что на самом деле лишь верхушка айсберга, речь пойдет о интерактивном дизайне.

Создаем интерактивные типографские эффекты
Поделиться в соцсетях:

Если вы заинтересованы в получении дополнительной информации о HTML5, то вот замечательный ресурс: Dive Into HTML5 by Mark Pilgrim

Разметка

HTML-разметка для нашего урока очень простая, так как мы будем делать всю работу при помощи JavaScript, это canvas элемент:

<canvas id="banner"></canvas>

JavaScript

Как говорилось, JavaScript будет делать всю тяжелую работу. Но в первую очередь, мы должны проверить, используют ли наши пользователи современный браузер, который поддерживает элемент canvas. Если он не поддерживается, то мы будем использовать статическое изображение. Чтобы проверить это мы будем использовать Modernizr.

Переменные

Начнем с определения некоторых переменных:

// The words to be written on the banner
var keyword     = "HONEY",
canvas, context,
bgCanvas, bgContext,
density     = 13,
particles     = [],
colour         = '#fff0a4',
mouse         = { x:0, y:0 },
isDrawing     = false,
canvasW, canvasH;

Небольшое пояснение: keyword здесь будет словом, которое вы хотите отобразить на баннере.

Canvas это переменная, которая будет содержать HTML-элемент canvas. Это будет присвоена позже. Context - это то что позволяет нам рисовать и писать в canvas.

Переменная density содержит количество пикселей которое мы хотим иметь (по горизонтали и вертикали) между каждой частью баннера.

Массив particles будет хранить все части и их параметры.

Переменная colour - это цвет каждой части.

Наконец, переменная isDrawing даёт нам знать, если мы наводим курсор мыши на баннер, и canvasW и canvasH являются соответственно шириной и высотой canvas.

Настройки баннера

Первый шаг состоит в вызове функции reload, которую мы также вызываем при изменении размеров окна:

this.initialize = function( canvas_id ) {
    reload( canvas_id );
    window.onresize = function(event) {
        reload( canvas_id );
    }
};

В reload функции мы инициализируем переменные canvas и context и устанавливаем соответствующие размеры. Затем мы вызываем функции prepare, setupParticles и draw.

var reload = function(canvas_id) {
    canvas = document.getElementById(canvas_id);
    if (!window.HTMLCanvasElement) return false;

    context = canvas.getContext('2d');
    canvasW = window.innerWidth;
    canvasH = 300;

    canvas.width = canvasW;
    canvas.height = canvasH;

    bgCanvas = document.createElement('canvas');
    bgContext = bgCanvas.getContext('2d');

    bgCanvas.width = canvasW;
    bgCanvas.height = canvasH;

    prepare();
    setupParticles();
    draw();
};

Первое, что нужно отметить, это то, что функция принимает строковую переменную, которая должна соответствовать ID элементу в HTML.

Как вы можете видеть, фоновый canvas и основной настроены на одинаковый размер. Почему мы используем два элемента canvas мы узнаем  в следующем разделе.

Background Canvas

ОК, теперь объясним, что мы делаем: причина, почему у нас два элемента canvas здесь.На фоновом canvas мы будем печатать текст или изображение. После этого мы будет проверять на данные изображения (пиксель за пикселем) холста.

var prepare = function() {
    // Выбираем шрифт и размер, который мы хотим.
    bgContext.font = "300px 'Jockey One'";

    // Fill the keyword text onto the canvas.
    bgContext.fillText(keyword, ( canvasW / 2 ) - ( Math.round( bgContext.measureText(keyword).width/2 ) ) , 260 );
};

Команда fillText принимает три параметра: первый из них текст, который мы пишем, второй и третий х и у координаты, соответственно. Далее, мы создадим частицы. Эти будут нарисованы на основном canvas, но сейчас мы просто сохраним их в наш массив частиц:

var setupParticles = function() {
    particles = [];       

    // Declare our local variables
    var imageData, image_Data,
    pixel,
    width = 0,
    i = 0,
    slide = false;

    // Get the image data - from (0,0) to the edges of the canvas
    imageData = bgContext.getImageData( 0, 0, canvasW, canvasH );
    image_Data= imageData.data;

    for (var height = 0; height < canvasH; height += density) {
        ++i;
        slide = ((i % 2) == 0);
        width = 0;
        if (slide == true) {
            width += 6;
        }

        // Iterate horizontally over the image data
        for (width; width < canvasW; width += density) {

            // Get the pixel located at our current iteration
            pixel = image_Data[ ( ( width + ( height * canvasW )) * 4 ) - 1 ];

            // Pixel has been drawn on.
            if (pixel == 255) {

                // Add the coodinates and colour to our particle array.
                particles.push({
                    colour : colour,
                    x : width,
                    y : height
                });

            }
        }
    }
};

Да, это большой кусок кода, я пройдусь по сложным деталям сейчас.

В действительности, все что мы делаем, это цикл по каждому n пикселя, где n - плотность, установленная в начале скрипта.

getImageData принимает четыре значения, х и у левого верхнего угла, а также правого нижнего угла. В нашем случае, мы установили два нуля (верхний левый угол) и ширину и высоту canvas, которые являются координатами нижнего правого угла. Эта функция возвращает очень большой список, содержащий данные о цвете каждого отдельного пикселя на холсте. Почему мы умножаем это на четыре? Потому что в этом списке каждый пиксель представлен четырьмя значениями: красный, зеленый, синий цвет и альфа-значение.

По умолчанию, весь canvas ImageData содержит длинный список нулей - использовав же fillText на этом холсте, пиксели теперь содержат нужные цвета.

Наконец, мы установили координаты х и у в словарь, который мы теперь будем использовать, чтобы рисовать наш баннер.

Рисуем баннер

Здесь мы, наконец, начнем рисовать. С помощью нашего списка х и у координат, сохраненных в массиве particles, мы можем нарисовать баннер.

var draw = function() {

    context.clearRect(0, 0, canvasW, canvasH);

    var dx, dy, sqrDist,
    scale = 1;

    for (var i = 0, len = particles.length; i < len ; ++i) {
        ...

        context.beginPath();

        context.moveTo( x, y - height / 2 );
        context.lineTo( x + width / 2, y - height / 4 );
        context.lineTo( x + width / 2, y + height / 4 );
        context.lineTo( x, y + height / 2 );
        context.lineTo( x - width / 2, y + height / 4 );
        context.lineTo( x - width / 2, y - height / 4 );
        context.lineTo( x, y - height / 2 );

        context.closePath();
        context.fill();
    }
};

Мы в цикле проходим по каждой из частиц, которые мы сохранили ранее, чтобы установить цвет и нарисовать фигуру в (х, у) точке.

При том, что у нас есть очень простой статический баннер ... теперь самое интересное, давайте добавим интерактивность.
Добавим интерактивности

Первое, что нам нужно будет сделать, так это отслеживать положение мыши пользователя, когда она наводится на баннер.

var mouse = {x:0, y:0, o: false};

Переменная мыши будет обновляться двумя функциями, одна для отслеживания движения, другая для отслеживания того не покинула ли мышь canvas элемент:

var MouseMove = function(e) {
    mouse.x = e.offsetX || ( e.layerX - canvas.offsetLeft );
    mouse.y = e.offsetY || ( e.layerY - canvas.offsetTop );
    if (!isDrawing) {
        isDrawing = true;
        drawTimeout = setTimeout( function() {
        draw();
        isDrawing = false;
        }, 60);
    }
};

var MouseOut = function(e) {
    isDrawing = false;
    clearTimeout( drawTimeout );
    draw();
};

Для того, чтобы сделать эту работу, мы также должны добавить JavaScript-события на наш canvas элемент. Они будут в нашей reload функции.

canvas.addEventListener('mousemove', MouseMove, false);
canvas.addEventListener('mouseout', MouseOut, false);

Теперь, когда мы можем отследить мышь, мы должны изменить немного нашу draw функцию, основываясь на том, как мы хотим взаимодействовать с мышью.

var p = particles[i];

dx = p.x - mouse.x;
dy = p.y - mouse.y;

// distance from mouse to particle
sqrDist = Math.sqrt( dx * dx + dy * dy );

(isDrawing) ? scale = Math.max( Math.min( 3 - ( sqrDist / 10 ), 10 ), 1 ) : scale = 1;

var width = density / scale - 4,
height = density,
x = p.x,
y = p.y;
context.fillStyle = p.colour;
...

Выше мы вычисляем расстояние между текущей частицей и мышью. Затем мы обновляем переменную scale уменьшая до 1 (что означает отсутствие масштабирования), и расстояние между мышью и частицей (но не больше 10).

Добавим немного цвета

Итак, у нас есть симпатичный рабочий баннер, но почему бы нам не добавить немного цвета. К счастью, мы уже сделали большую часть работы, и здесь нам нужно только изменить 2 строки.

// A variable to store each of the colors we want to use
var colors = ['#fff0a4', '#ffe98f', '#ffcf52', '#fbad1d', '#c48d1c'];
...

// When creating the particles, we assign a color from this list.
color: colors[Math.floor(Math.random() * colors.length)],

Вот и всё! Уникальный, интерактивный и красочный баннер, готов для вас. Взгляните на демо, чтобы увидеть что у нас в результате получилось.

Новый комментарий

Имя:
Для редактирования комментария осталось 10 минут
Комментарии отсутствуют