Как я могу оживить рисование текста на веб-странице?


229

Я хочу иметь веб-страницу с одним центрированным словом.

Я хочу, чтобы это слово было нарисовано с помощью анимации, чтобы страница «записывала» слово так же, как и мы, то есть оно начинается в одной точке и рисует линии и кривые с течением времени, так что конечным результатом является глиф.

Мне все равно, будет ли это сделано с <canvas>помощью DOM, и мне все равно, будет ли это сделано с помощью JavaScript или CSS. Отсутствие jQuery было бы неплохо, но не обязательно.

Как я могу это сделать? Я искал исчерпывающе без удачи.


2
Я немного подумал о том, как на самом деле «
написать

Что-то действительно похожее в статье codropsдемонстрацией в тимпане )
Francisco Presencia

1
Когда-то я делал эту анимацию во Flash, используя анимированные маски спрайтов. Вам нужно анимировать маску, что означает, что она постепенно раскрывает текст. Анимация будет сделана из рамок маски.
Tiberiu-Ionuț Stan

Конечно, вы можете разбить текст на кривые. Вы должны будете сделать это, используя перед использованием SVG и редактор SVG (Illustrator или что-то еще, что может создать SVG вашего текста). Я не знаю, поддерживают ли SVG маски, но если они это сделают, это станет намного легче анимировать.
Tiberiu-Ionuț Stan

Используйте SVG и манипулируйте кодом SVG с помощью JavaScript для создания анимации.
Демц

Ответы:


264

Я хочу, чтобы это слово было нарисовано с помощью анимации, чтобы страница «записывала» слово так же, как мы

Холст версия

Это будет рисовать отдельные символы больше, чем можно было бы написать вручную. Он использует длинный штрих-шаблон, в котором порядок включения / выключения меняется со временем на символ. Он также имеет параметр скорости.

снимок
Пример анимации (см. Демо ниже)

Чтобы повысить реалистичность и органичность, я добавил случайный межбуквенный интервал, смещение по оси y, прозрачность, очень тонкое вращение и, наконец, использование уже «рукописного» шрифта. Они могут быть упакованы как динамические параметры, чтобы обеспечить широкий диапазон «стилей письма».

Для еще более реалистичного вида потребовались бы данные пути, которых нет по умолчанию. Но это короткий и эффективный фрагмент кода, который приближает рукописное поведение и прост в реализации.

Как это устроено

Определяя рисунок тире, мы можем создавать марширующих муравьев, пунктирные линии и так далее. Воспользовавшись этим, определив очень длинную точку для точки «выкл» и постепенно увеличивая точку «вкл», это создаст иллюзию рисования линии при нанесении штрихов при анимации длины точки.

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

Для букв, состоящих из более чем одного пути (например, O, R, P и т. Д.), Как один для контура, один для полой части, линии будут отображаться одновременно. Мы не можем ничего с этим поделать с помощью этой техники, так как для этого потребуется доступ к каждому сегменту пути, который будет обводиться отдельно.

Совместимость

Для браузеров, которые не поддерживают элемент canvas, между тегами можно разместить альтернативный способ отображения текста, например стилизованный текст:

<canvas ...>
    <div class="txtStyle">STROKE-ON CANVAS</div>
</canvas>

демонстрация

Это производит живой анимированный удар ( без зависимостей ) -

var ctx = document.querySelector("canvas").getContext("2d"),
    dashLen = 220, dashOffset = dashLen, speed = 5,
    txt = "STROKE-ON CANVAS", x = 30, i = 0;

ctx.font = "50px Comic Sans MS, cursive, TSCu_Comic, sans-serif"; 
ctx.lineWidth = 5; ctx.lineJoin = "round"; ctx.globalAlpha = 2/3;
ctx.strokeStyle = ctx.fillStyle = "#1f2f90";

(function loop() {
  ctx.clearRect(x, 0, 60, 150);
  ctx.setLineDash([dashLen - dashOffset, dashOffset - speed]); // create a long dash mask
  dashOffset -= speed;                                         // reduce dash length
  ctx.strokeText(txt[i], x, 90);                               // stroke letter

  if (dashOffset > 0) requestAnimationFrame(loop);             // animate
  else {
    ctx.fillText(txt[i], x, 90);                               // fill final letter
    dashOffset = dashLen;                                      // prep next char
    x += ctx.measureText(txt[i++]).width + ctx.lineWidth * Math.random();
    ctx.setTransform(1, 0, 0, 1, 0, 3 * Math.random());        // random y-delta
    ctx.rotate(Math.random() * 0.005);                         // random rotation
    if (i < txt.length) requestAnimationFrame(loop);
  }
})();
canvas {background:url(http://i.imgur.com/5RIXWIE.png)}
<canvas width=630></canvas>


21
Я один схожу с ума по этому поводу? Выглядит так реально, по крайней мере, намного лучше, чем первый ответ, и ближе всего к вопросу спрашивающего.
Хофи

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

Как мы можем сделать это для нескольких строк и длинного текстового блока?
Саад Фарук

1
@ K3N Да, на самом деле это был приятный штрих: p Отличная работа.
keyser

1
@ AliAl-arnous, вы можете установить x на противоположном конце, вычесть ширину символа вместо сложения, преобразовать с отрицательным отрицательным пространством и изменить clearRect, чтобы очистить на другой стороне символа.

216

Изменить 2019


Я создал библиотеку JavaScript, которая может создавать реалистичные анимации. Он прост в использовании и требует специального файла JSON, который действует как шрифт.

var vara = new Vara("#container", "https://rawcdn.githack.com/akzhy/Vara/ed6ab92fdf196596266ae76867c415fa659eb348/fonts/Satisfy/SatisfySL.json", [{
  text: "Hello World!!",
  fontSize: 48,
  y:10
}, {
  text: "Realistic Animations",
  fontSize: 34,
  color:"#f44336"
}], {
  strokeWidth: 2,
  textAlign:"center"
});
#container {
  padding: 30px;
}
<script src="https://rawcdn.githack.com/akzhy/Vara/16e30acca2872212e28735cfdbaba696a355c780/src/vara.min.js"></script>
<div id="container"></div>

Извлекает страницу GitHub для документации и примеров. И Codepen


Предыдущий ответ

В приведенном ниже примере используется snap.js для динамического создания tspanэлементов, а затем анимировать каждый из них stroke-dashoffset.

Предыдущий ответ


Вы можете сделать что-то подобное, используя svg stroke-dasharray

Без keyframesанимации вы можете сделать что-то вроде этого

А для поддержки IE вы можете использовать jquery / javascript


4
Вау, это действительно интересно. Я взял ваш оригинальный фрагмент кода и немного улучшил его, удалив дублирующиеся свойства CSS, используя смещения в процентах и ​​значения черточки, и изменив ширину штриха, чтобы сделать его более понятным, как работает код: jsfiddle.net/Ajedi32/gdc4azLn / 1 Не стесняйтесь редактировать любое из этих улучшений в своем ответе, если хотите.
Ajedi32

2
это одно из самых грандиозных решений этого вопроса: SVG лучше, чем canvas (+1), поскольку в случае, если браузер его не поддерживает, вместо него будет отображаться текст.
Джеффри ТхГинтоки

3
@JefferyThaGintoki Вы можете сделать это и с помощью canvas, просто поместите текст между тегами canvas, если canvas не поддерживается, вместо него появится текст (или анимированный gif, как в других ответах, показанных в основном тексте). Если браузер не поддерживает canvas, он, вероятно, также не будет поддерживать svg.
torox

1
Я думаю, что использование SVG-текста прекрасно, однако мне интересно, возможно ли добавить заливку в какой-то момент? просто наброски букв не выглядят хорошо во всех проектах, ура! и, конечно, +1 к этому ответу
randomguy04

1
@ randomguy04 Проверьте первый фрагмент, я отредактировал его, чтобы добавить эффект заливки. Это делается путем добавления $(this).css('fill', 'red')в качестве обратного вызова анимации
Акшай

2

Только CSS:

@keyframes fadein_left {
  from {
    left: 0;
  }
  to {
    left: 100%;
  }
}

#start:before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0%;
  opacity: 0.7;
  height: 25px;
  background: #fff;
  animation: fadein_left 3s;
}
<div id="start">
  some text some text some text some text some text
</div>


0

После многих тестов, вот некоторые заметки. Цель состоит в том, чтобы отображать быстрые текстовые данные с наименьшей блокировкой, на тяжелых страницах DOM, требующих взаимодействия с пользователем.

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

Самый медленный : innerHTMLи встроенный стиль. DOM пересчитывается на каждой итерации. Браузер усердно работает, чтобы сохранить поезд. Он быстро перестает работать, вызывая утечки памяти и зависает:

setInterval(function(){
  out.innerHTML = `<span style="position:fixed;top:${~~(Math.random() * 220)}px">${Math.random() * 1000}<span>`
},1)
<h1 id="out"></h1>

Путь лучше : использование textContent, requestAnimationFrameи веб - анимации апи. Это идет намного лучше, это очевидно на тяжелых страницах DOM. Взаимодействие с пользователем не блокирует перерисовки. Некоторые перерисовки могут быть пропущены, чтобы интерфейс хорошо реагировал.

let job
const paint = () => {
  job = requestAnimationFrame(paint)
  out.textContent = Math.random() * 1000
  out.animate([{top: ~~(Math.random() * 220)+"px"},{top:0}],{duration: 1,iterations: 1})
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(paint)
#out{
position: fixed}
<h1 id="out"></h1>

В приведенном выше примере DOM все еще пересчитывается для переполнения текста. Мы видим, что отладчик сильно мигает. Это действительно важно для каскадных элементов! Это все еще может замедлить JavaScript и пользовательские прокрутки.

введите описание изображения здесь

Полная мощность : можно использовать только css для обновления данных с помощью contentправила css и переменных css. Текст тогда не будет доступен для выбора.

let job
const paint = () => {
  job = requestAnimationFrame(paint)
  out.setAttribute('data-before', Math.random() * 1000)
  out.animate([{top: ~~(Math.random() * 220)+"px"},{top:0}],{duration: 1,iterations: 1})
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(paint)
#out{
  position: fixed
  
  }
#out:before {
   content: attr(data-before)
 }
<h1 id="out"></h1>

введите описание изображения здесь

Мои тесты показывают большие улучшения, движок javascript быстро пропускает другие задачи. Иногда это может начаться немного медленнее, чем в приведенном выше примере. Но помимо этого, это не блокирует пользовательские прокрутки, и отладчик также нравится, больше никаких переходов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.