D3: переход текста в стиле пишущей машинки
В этом jsfiddle
, метка переходит от одного текста к другому, уменьшая шрифт старого текста и, в свою очередь, увеличивая шрифт нового текста.
Тем не менее, я хотел бы, чтобы новый текст apperar "печатная машинка", как в этом jsfiddle
, Как написать собственный текстовый интерполятор D3, который позволит переходить текст таким способом "пишущей машинки"?
3 ответа
Интересные идеи, оба выполняют свою работу, но для этого есть специальный способ для d3: пользовательская функция анимации.
Скрипка здесь: http://jsfiddle.net/QbysN/3/
Код:
function transition() {
d3.select('text').transition()
.duration(5000)
.ease("linear")
.tween("text", function () {
var newText = data[i];
var textLength = newText.length;
return function (t) {
this.textContent = newText.substr(0,
Math.round( t * textLength) );
};
});
i = (i + 1) % data.length;
}
Внешняя функция, которую вы передаете .tween()
называется фабрикой анимации, потому что она создает функцию анимации для каждого элемента. Он выполняется один раз для каждого элемента (и обычно использует данные и индекс элемента в качестве параметров) в начале перехода. Он запускает любые расчеты установки и затем возвращает функцию анимации, которая будет использоваться во время перехода.
Возвращенная функция анимации также называется интерполятором, поскольку она вычисляет промежуточные значения. В этом случае это:
function (t) {
this.textContent = newText.substr(0, Math.round( t * textLength) );
};
Эта функция будет вызываться при каждом "тике" перехода, и ей будет передано значение от 0 до 1, представляющее, как далеко через переход предполагается получить результат. (Скорость, с которой 0 изменяется на 1, будет варьироваться в зависимости от параметра замедления, я использовал линейное ослабление для постоянной скорости типа.)
Когда вы задаете пользовательские функции анимации для атрибутов или стилей, функция анимации возвращает значение, которое будет использоваться для этого атрибута или стиля в этой точке перехода. Для общего transition.tween()
возвращаемые значения не используются, ваша функция должна сама вносить изменения - что я делаю, непосредственно устанавливая textContent
свойство элемента. Я установил его на подстроку целевого текста, где количество символов в подстроке определяется t
Параметр (который всегда находится в диапазоне от 0 до 1) и длина текста, так что весь текст набирается по длине перехода.
PS Вы также можете повеселиться с функцией ослабления. Легкость "отказов" делает вид, что машинистка не уверена в том, что они пишут:
Я дал этому шанс. Должен сказать, что у меня нет опыта D3. Я попытался получить комбинацию двух скрипок, которые ты показал. Я думаю, что нужно еще кое-что сделать и когда прекратить печатать, но это должно быть тривиально.
Проверьте jsFiddle
HTML:
<div id="writer">
<span id='sentence'></span>
<span id='char'></span>
</div>
CSS:
#writer{
border: 1px solid black;
width:300px;
min-height: 200px;
margin: auto;
}
span
{
float:left;
}
JavaScript:
var text = "Hello World! I'm some typed text!";
var counter = 0;
var speed = 50;
function type()
{
var sentence = document.getElementById("sentence");
var lastText = sentence.innerHTML;
var nextChar = text.charAt(counter);
counter++;
transition(nextChar,
function()
{
lastText+=nextChar;
sentence.innerHTML = lastText;
setTimeout(type, speed);
});
}
function transition(char, onComplete) {
d3.select('#char').transition()
.text("")
.duration(300)
.style("font-size","1px")
.transition()
.duration(300)
.text(char)
.style("font-size","16px")
.each("end", onComplete);
}
type();
Я думал, что текст будет легче печатать автоматически. Поэтому я перебрал каждый символ и вызвал метод перехода. Я добавил 2 аргумента к этому row
а также column
чтобы я мог дать соответствующие задержки.
data.forEach(function(d,row) {
d.split("").forEach(function(d,column) {
transition(row,column);
});
});
function transition(row,column) {
d3.select('text').datum(data[row].split("").slice(0,column+1))
.transition()
.delay(function(d) { return (row*5000) + (column*50); } )
.text(function(d){return d.join("");});
}
Попробуйте эту скрипку: http://jsfiddle.net/QbysN/2/