<div id='settings'>
<button id='go'>Restart</button>
</div>
<div id="container"></div>
<script src="https://unpkg.com/konva@7.0.3/konva.min.js"></script>
body {
margin: 14px;
padding: 10px;
font: 12pt Verdana, Arial, sans-serif;
}
#settings {
position: absolute;
z-index: 100;
padding: 2px;
}
#container {
position: absolute;
padding: 2px;
}
th {
text-align: left;
padding-top: 5px;
background-color: silver;
}
td {
padding-left:15px;
}
button {
z-index: 100;
}
console.clear;
let stage = null,
layer = null,
wordList = [],
timerSpan = $('#timer'),
frameRateSpan = $('#frameRate');
setup(); // boring stuff to set up the stage and words.
console.log('Animate ' + wordList.length + ' words' )
let easing = new Easings();
stage.draw();
animate();
function animate(){
// These are the values affecting the animation
let
// initial spiral outer circle radius - reduces per animation frame.
maxRadius = 40,
// duration of animation in ms
duration = 2000,
// angle to traverse in the duration, in radians.
rotationDegrees = 720 * Math.PI/180;
layer.find('Text').opacity(0); // fade out the text
let anim = new Konva.Animation(function(frame) {
let time = frame.time;
let t1 = performance.now()
// for each word...
for (let i = 0; i < wordList.length; i++){
let
// calculate the new radius
radius = easing.EaseInCubic(frame.time, maxRadius, -maxRadius, duration),
// and new angle - note all the words have a different initial angle value
angle = wordList[i].angle + easing.EaseInCubic(frame.time, 0, rotationDegrees, duration),
// and the final position we are destined for
pos = wordList[i].finalPosition,
// simple trig to calculate the x,y position of the word at this frame
x = pos.x + (Math.sin(angle) * radius),
y = pos.y - (Math.cos(angle) * radius);
// Apply the position to the word
wordList[i].shape.position({x: x, y: y});
// fade the text into view as the animation progresses
wordList[i].shape.opacity(frame.time / duration);
// If we are at the end of the animation ensure we hit the final target position
if (time >= duration){
wordList[i].shape.position(wordList[i].finalPosition);
}
}
// If we are at the end of the animation then stop it !
if (time > duration){
anim.stop()
}
}, layer);
anim.start();
}
$('#go').on('click', function(){
animate();
})
function setup(){
stage = new Konva.Stage({ // Set up a stage
container: "container",
width: window.innerWidth,
height: window.innerHeight,
scaleX: 2,
scaleY: 2,
offset: {x: -70, y: -20}
});
// add a layer to draw on
layer = new Konva.Layer();
let posData = `{"id":"","fontInfo":{"fontName":"Arial","fontSize":"10","fontColor":"Black","fontBold":""},"paras":[{"id":"para-8","sentences":[{"id":"sentence-0","lines":[{"id":"line-0","words":[{"box":[25.0001,25.0001,33.3546,15.0001],"text":"Ground"},{"box":[58.3546,25.0001,2.7784,15.0001],"text":" "},{"box":[61.1329,25.0001,32.2364,15.0001],"text":"Control"},{"box":[93.3692,25.0001,2.7784,15.0001],"text":" "},{"box":[96.1476,25.0001,8.3399,15.0001],"text":"to"},{"box":[104.4874,25.0001,2.7784,15.0001],"text":" "},{"box":[107.2657,25.0001,25.005,15.0001],"text":"Major"},{"box":[132.2706,25.0001,2.7784,15.0001],"text":" "},{"box":[135.0489,25.0001,18.8917,15.0001],"text":"Tom"}]}]},{"id":"sentence-1","lines":[{"id":"line-0","words":[{"box":[25.0001,40.0001,33.3546,15.0001],"text":"Ground"},{"box":[58.3546,40.0001,2.7784,15.0001],"text":" "},{"box":[61.1329,40.0001,32.2364,15.0001],"text":"Control"},{"box":[93.3692,40.0001,2.7784,15.0001],"text":" "},{"box":[96.1476,40.0001,8.3399,15.0001],"text":"to"},{"box":[104.4874,40.0001,2.7784,15.0001],"text":" "},{"box":[107.2657,40.0001,25.005,15.0001],"text":"Major"},{"box":[132.2706,40.0001,2.7784,15.0001],"text":" "},{"box":[135.0489,40.0001,18.8917,15.0001],"text":"Tom"}]}]},{"id":"sentence-2","lines":[{"id":"line-0","words":[{"box":[25.0001,55.0001,21.1231,15.0001],"text":"Take"},{"box":[46.1231,55.0001,2.7784,15.0001],"text":" "},{"box":[48.9015,55.0001,19.4532,15.0001],"text":"your"},{"box":[68.3546,55.0001,2.7784,15.0001],"text":" "},{"box":[71.1329,55.0001,30.5763,15.0001],"text":"protein"},{"box":[101.7091,55.0001,2.7784,15.0001],"text":" "},{"box":[104.4874,55.0001,17.2267,15.0001],"text":"pills"},{"box":[121.714,55.0001,2.7784,15.0001],"text":" "},{"box":[124.4923,55.0001,16.6847,15.0001],"text":"and"},{"box":[141.1769,55.0001,2.7784,15.0001],"text":" "},{"box":[143.9552,55.0001,13.9015,15.0001],"text":"put"},{"box":[157.8565,55.0001,2.7784,15.0001],"text":" "},{"box":[160.6349,55.0001,19.4532,15.0001],"text":"your"},{"box":[180.088,55.0001,2.7784,15.0001],"text":" "},{"box":[182.8663,55.0001,30.0147,15.0001],"text":"helmet"},{"box":[212.881,55.0001,2.7784,15.0001],"text":" "},{"box":[215.6593,55.0001,11.1231,15.0001],"text":"on"}]}]},{"id":"sentence-3","lines":[{"id":"line-0","words":[{"box":[25.0001,70.0001,33.3546,15.0001],"text":"Ground"},{"box":[58.3546,70.0001,2.7784,15.0001],"text":" "},{"box":[61.1329,70.0001,32.2364,15.0001],"text":"Control"},{"box":[93.3692,70.0001,2.7784,15.0001],"text":" "},{"box":[96.1476,70.0001,8.3399,15.0001],"text":"to"},{"box":[104.4874,70.0001,2.7784,15.0001],"text":" "},{"box":[107.2657,70.0001,25.005,15.0001],"text":"Major"},{"box":[132.2706,70.0001,2.7784,15.0001],"text":" "},{"box":[135.0489,70.0001,18.8917,15.0001],"text":"Tom"}]}]},{"id":"sentence-4","lines":[{"id":"line-0","words":[{"box":[25.0001,85.0001,58.9112,15.0001],"text":"Commencing"},{"box":[83.9112,85.0001,2.7784,15.0001],"text":" "},{"box":[86.6896,85.0001,51.1476,15.0001],"text":"countdown,"},{"box":[137.837,85.0001,2.7784,15.0001],"text":" "},{"box":[140.6153,85.0001,35.0294,15.0001],"text":"engines"},{"box":[175.6446,85.0001,2.7784,15.0001],"text":" "},{"box":[178.423,85.0001,11.1231,15.0001],"text":"on"}]}]},{"id":"sentence-5","lines":[{"id":"line-0","words":[{"box":[25.0001,100.0001,28.3448,15.0001],"text":"Check"},{"box":[53.3448,100.0001,2.7784,15.0001],"text":" "},{"box":[56.1231,100.0001,31.6896,15.0001],"text":"ignition"},{"box":[87.8126,100.0001,2.7784,15.0001],"text":" "},{"box":[90.5909,100.0001,16.6847,15.0001],"text":"and"},{"box":[107.2755,100.0001,2.7784,15.0001],"text":" "},{"box":[110.0538,100.0001,18.8917,15.0001],"text":"may"},{"box":[128.9454,100.0001,2.7784,15.0001],"text":" "},{"box":[131.7237,100.0001,25.8106,15.0001],"text":"God's"},{"box":[157.5343,100.0001,2.7784,15.0001],"text":" "},{"box":[160.3126,100.0001,18.3448,15.0001],"text":"love"},{"box":[178.6573,100.0001,2.7784,15.0001],"text":" "},{"box":[181.4356,100.0001,11.1231,15.0001],"text":"be"},{"box":[192.5587,100.0001,2.7784,15.0001],"text":" "},{"box":[195.337,100.0001,17.7833,15.0001],"text":"with"},{"box":[213.1202,100.0001,2.7784,15.0001],"text":" "},{"box":[215.8985,100.0001,16.1231,15.0001],"text":"you"}]}]}]},{"id":"para-8","sentences":[{"id":"sentence-0","lines":[{"id":"line-0","words":[{"box":[25.0001,140.0001,56.7042,15.0001],"text":"[spoken]Ten,"},{"box":[81.7042,140.0001,2.7784,15.0001],"text":" "},{"box":[84.4825,140.0001,23.3448,15.0001],"text":"Nine,"},{"box":[107.8272,140.0001,2.7784,15.0001],"text":" "},{"box":[110.6056,140.0001,25.5714,15.0001],"text":"Eight,"},{"box":[136.1769,140.0001,2.7784,15.0001],"text":" "},{"box":[138.9552,140.0001,31.1329,15.0001],"text":"Seven,"},{"box":[170.088,140.0001,2.7784,15.0001],"text":" "},{"box":[172.8663,140.0001,16.67,15.0001],"text":"Six,"},{"box":[189.5362,140.0001,2.7784,15.0001],"text":" "},{"box":[192.3146,140.0001,21.67,15.0001],"text":"Five,"},{"box":[213.9845,140.0001,2.7784,15.0001],"text":" "},{"box":[216.7628,140.0001,22.7882,15.0001],"text":"Four,"},{"box":[239.5509,140.0001,2.7784,15.0001],"text":" "},{"box":[242.3292,140.0001,28.9015,15.0001],"text":"Three,"}]},{"id":"line-1","words":[{"box":[25.0001,155.0001,21.1183,15.0001],"text":"Two,"},{"box":[46.1183,155.0001,2.7784,15.0001],"text":" "},{"box":[48.8966,155.0001,21.6798,15.0001],"text":"One,"},{"box":[70.5763,155.0001,2.7784,15.0001],"text":" "},{"box":[73.3546,155.0001,24.2774,15.0001],"text":"Liftoff"}]}]}]},{"id":"para-8","sentences":[{"id":"sentence-0","lines":[{"id":"line-0","words":[{"box":[25.0001,195.0001,18.8917,15.0001],"text":"This"},{"box":[43.8917,195.0001,2.7784,15.0001],"text":" "},{"box":[46.67,195.0001,7.2218,15.0001],"text":"is"},{"box":[53.8917,195.0001,2.7784,15.0001],"text":" "},{"box":[56.67,195.0001,33.3546,15.0001],"text":"Ground"},{"box":[90.0245,195.0001,2.7784,15.0001],"text":" "},{"box":[92.8028,195.0001,32.2364,15.0001],"text":"Control"},{"box":[125.0392,195.0001,2.7784,15.0001],"text":" "},{"box":[127.8175,195.0001,8.3399,15.0001],"text":"to"},{"box":[136.1573,195.0001,2.7784,15.0001],"text":" "},{"box":[138.9356,195.0001,25.005,15.0001],"text":"Major"},{"box":[163.9405,195.0001,2.7784,15.0001],"text":" "},{"box":[166.7189,195.0001,18.8917,15.0001],"text":"Tom"}]}]},{"id":"sentence-1","lines":[{"id":"line-0","words":[{"box":[25.0001,210.0001,29.3458,15.0001],"text":"You've"},{"box":[54.3458,210.0001,2.7784,15.0001],"text":" "},{"box":[57.1241,210.0001,23.8966,15.0001],"text":"really"},{"box":[81.0206,210.0001,2.7784,15.0001],"text":" "},{"box":[83.7989,210.0001,25.0147,15.0001],"text":"made"},{"box":[108.8136,210.0001,2.7784,15.0001],"text":" "},{"box":[111.5919,210.0001,13.9015,15.0001],"text":"the"},{"box":[125.4933,210.0001,2.7784,15.0001],"text":" "},{"box":[128.2716,210.0001,25.5763,15.0001],"text":"grade"}]}]},{"id":"sentence-2","lines":[{"id":"line-0","words":[{"box":[25.0001,225.0001,17.7931,15.0001],"text":"And"},{"box":[42.7931,225.0001,2.7784,15.0001],"text":" "},{"box":[45.5714,225.0001,13.9015,15.0001],"text":"the"},{"box":[59.4728,225.0001,2.7784,15.0001],"text":" "},{"box":[62.2511,225.0001,30.5763,15.0001],"text":"papers"},{"box":[92.8272,225.0001,2.7784,15.0001],"text":" "},{"box":[95.6056,225.0001,21.1231,15.0001],"text":"want"},{"box":[116.7286,225.0001,2.7784,15.0001],"text":" "},{"box":[119.5069,225.0001,8.3399,15.0001],"text":"to"},{"box":[127.8468,225.0001,2.7784,15.0001],"text":" "},{"box":[130.6251,225.0001,23.3448,15.0001],"text":"know"},{"box":[153.9698,225.0001,2.7784,15.0001],"text":" "},{"box":[156.7481,225.0001,28.9064,15.0001],"text":"whose"},{"box":[185.6544,225.0001,2.7784,15.0001],"text":" "},{"box":[188.4327,225.0001,23.8917,15.0001],"text":"shirts"},{"box":[212.3243,225.0001,2.7784,15.0001],"text":" "},{"box":[215.1026,225.0001,16.1231,15.0001],"text":"you"},{"box":[231.2257,225.0001,2.7784,15.0001],"text":" "},{"box":[234.004,225.0001,21.6749,15.0001],"text":"wear"}]}]},{"id":"sentence-3","lines":[{"id":"line-0","words":[{"box":[25.0001,240.0001,20.005,15.0001],"text":"Now"},{"box":[45.005,240.0001,2.7784,15.0001],"text":" "},{"box":[47.7833,240.0001,11.9093,15.0001],"text":"it's"},{"box":[59.6925,240.0001,2.7784,15.0001],"text":" "},{"box":[62.4708,240.0001,18.8917,15.0001],"text":"time"},{"box":[81.3624,240.0001,2.7784,15.0001],"text":" "},{"box":[84.1407,240.0001,8.3399,15.0001],"text":"to"},{"box":[92.4806,240.0001,2.7784,15.0001],"text":" "},{"box":[95.2589,240.0001,23.9064,15.0001],"text":"leave"},{"box":[119.1651,240.0001,2.7784,15.0001],"text":" "},{"box":[121.9435,240.0001,13.9015,15.0001],"text":"the"},{"box":[135.8448,240.0001,2.7784,15.0001],"text":" "},{"box":[138.6231,240.0001,34.4679,15.0001],"text":"capsule"},{"box":[173.0909,240.0001,2.7784,15.0001],"text":" "},{"box":[175.8692,240.0001,5.0001,15.0001],"text":"if"},{"box":[180.8692,240.0001,2.7784,15.0001],"text":" "},{"box":[183.6476,240.0001,16.1231,15.0001],"text":"you"},{"box":[199.7706,240.0001,2.7784,15.0001],"text":" "},{"box":[202.5489,240.0001,20.0147,15.0001],"text":"dare"}]}]}]},{"id":"para-8","sentences":[{"id":"sentence-0","lines":[{"id":"line-0","words":[{"box":[25.0001,280.0001,18.8917,15.0001],"text":"This"},{"box":[43.8917,280.0001,2.7784,15.0001],"text":" "},{"box":[46.67,280.0001,7.2218,15.0001],"text":"is"},{"box":[53.8917,280.0001,2.7784,15.0001],"text":" "},{"box":[56.67,280.0001,25.005,15.0001],"text":"Major"},{"box":[81.6749,280.0001,2.7784,15.0001],"text":" "},{"box":[84.4532,280.0001,18.8917,15.0001],"text":"Tom"},{"box":[103.3448,280.0001,2.7784,15.0001],"text":" "},{"box":[106.1231,280.0001,8.3399,15.0001],"text":"to"},{"box":[114.463,280.0001,2.7784,15.0001],"text":" "},{"box":[117.2413,280.0001,33.3546,15.0001],"text":"Ground"},{"box":[150.5958,280.0001,2.7784,15.0001],"text":" "},{"box":[153.3741,280.0001,32.2364,15.0001],"text":"Control"}]}]},{"id":"sentence-1","lines":[{"id":"line-0","words":[{"box":[25.0001,295.0001,13.0177,15.0001],"text":"I'm"},{"box":[38.0177,295.0001,2.7784,15.0001],"text":" "},{"box":[40.796,295.0001,37.8077,15.0001],"text":"stepping"},{"box":[78.6036,295.0001,2.7784,15.0001],"text":" "},{"box":[81.3819,295.0001,33.9161,15.0001],"text":"through"},{"box":[115.298,295.0001,2.7784,15.0001],"text":" "},{"box":[118.0763,295.0001,13.9015,15.0001],"text":"the"},{"box":[131.9776,295.0001,2.7784,15.0001],"text":" "},{"box":[134.756,295.0001,20.0147,15.0001],"text":"door"}]}]},{"id":"sentence-2","lines":[{"id":"line-0","words":[{"box":[25.0001,310.0001,17.7931,15.0001],"text":"And"},{"box":[42.7931,310.0001,2.7784,15.0001],"text":" "},{"box":[45.5714,310.0001,13.0177,15.0001],"text":"I'm"},{"box":[58.589,310.0001,2.7784,15.0001],"text":" "},{"box":[61.3673,310.0001,32.2462,15.0001],"text":"floating"},{"box":[93.6134,310.0001,2.7784,15.0001],"text":" "},{"box":[96.3917,310.0001,7.7833,15.0001],"text":"in"},{"box":[104.1749,310.0001,2.7784,15.0001],"text":" "},{"box":[106.9532,310.0001,5.5616,15.0001],"text":"a"},{"box":[112.5147,310.0001,2.7784,15.0001],"text":" "},{"box":[115.2931,310.0001,21.67,15.0001],"text":"most"},{"box":[136.963,310.0001,2.7784,15.0001],"text":" "},{"box":[139.7413,310.0001,35.0196,15.0001],"text":"peculiar"},{"box":[174.7608,310.0001,2.7784,15.0001],"text":" "},{"box":[177.5392,310.0001,17.7833,15.0001],"text":"way"}]}]},{"id":"sentence-3","lines":[{"id":"line-0","words":[{"box":[25.0001,325.0001,17.7931,15.0001],"text":"And"},{"box":[42.7931,325.0001,2.7784,15.0001],"text":" "},{"box":[45.5714,325.0001,13.9015,15.0001],"text":"the"},{"box":[59.4728,325.0001,2.7784,15.0001],"text":" "},{"box":[62.2511,325.0001,21.67,15.0001],"text":"stars"},{"box":[83.921,325.0001,2.7784,15.0001],"text":" "},{"box":[86.6993,325.0001,18.3448,15.0001],"text":"look"},{"box":[105.044,325.0001,2.7784,15.0001],"text":" "},{"box":[107.8224,325.0001,18.8917,15.0001],"text":"very"},{"box":[126.714,325.0001,2.7784,15.0001],"text":" "},{"box":[129.4923,325.0001,35.9522,15.0001],"text":"different"},{"box":[165.4444,325.0001,2.7784,15.0001],"text":" "},{"box":[168.2228,325.0001,24.463,15.0001],"text":"today"}]}]}]}]}`,
wordNo = 0;
textInfo = JSON.parse(posData);
// Loading the text
let wordMax = 199, notAtLimit = true;
for (i = 0; i < textInfo.paras.length && notAtLimit; i++){
let para = textInfo.paras[i]
for (j = 0; j < para.sentences.length && notAtLimit; j++){
let sentence = para.sentences[j]
for (m = 0; m < sentence.lines.length && notAtLimit; m++){
let line = sentence.lines[m]
for (n = 0; n < line.words.length && notAtLimit; n++){
let word = line.words[n];
word.box[2] = word.text === "•" ? 10 : word.box[2];
let wordShape = new Konva.Text({
x: word.box[0],
y: word.box[1],
width: word.box[2],
height: word.box[3],
fontFamily: textInfo.fontInfo.fontName,
fontSize: textInfo.fontInfo.fontSize,
fill: textInfo.fontInfo.fontColor,
text: word.text,
perfectDrawEnabled: false,
transformsEnabled: 'position',
shadowEnabled: false,
shadowForStrokeEnabled: false
})
wordNo = wordNo + 1;
layer.add(wordShape);
wordList.push({
shape: wordShape,
finalPosition: wordShape.position(),
angle: Math.random() * 720 // set a random starting angle different for each word.
});
notAtLimit = (wordNo < wordMax);
}
}
}
layer.batchDraw();
stage.draw();
}
stage.add(layer);
stage.draw();
}
function Easings() {
let easings = {
//
// Linear
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
linear : function(t, b, c, d) {
return c * t / d + b;
},
//
// Ease In Quadratic
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseInQuad: function(t, b, c, d) {
t /= d;
return c * t * t + b;
},
//
// Ease Out Quadratic
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseOutQuad: function(t, b, c, d) {
t /= d;
return -c * t * (t - 2) + b;
},
//
// Ease In Out Quadratic
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseInOutQuad: function(t, b, c, d) {
t /= d / 2;
if(t < 1) {
return c / 2 * t * t + b;
}
t--;
return -c / 2 * (t * (t - 2) - 1) + b;
},
//
// Ease In Cubic
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseInCubic: function(t, b, c, d) {
t /= d;
return c * t * t * t + b;
},
//
// Ease Out Cubic
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseOutCubic: function(t, b, c, d) {
t /= d;
t--;
return c * (t * t * t + 1) + b;
},
//
// Ease In Out Cubic
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseInOutCubic: function(t, b, c, d) {
t /= d / 2;
if (t < 1) {
return c / 2 * t * t * t + b;
}
t -= 2;
return c / 2 * (t * t * t + 2) + b;
},
//
// Ease In Exponential
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseInExpo: function(t, b, c, d) {
return c * Math.pow(2, 10 * (t / d - 1)) + b;
},
//
// Ease Out Exponential
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseOutExpo: function(t, b, c, d) {
return c * (-Math.pow(2, -10 * t / d) + 1) + b;
},
//
// Ease In Out Exponential
// @param t: current time
// @param b: begin position
// @param c: change from end to begin position
// @param d: duration
//
EaseInOutExpo: function(t, b, c, d) {
t /= d / 2;
if (t < 1) {
return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
}
t--;
return c / 2 * (-Math.pow(2, -10 * t) + 2) + b;
}
}
return easings;
}
This Pen doesn't use any external CSS resources.