Skip to content

Instantly share code, notes, and snippets.

@EE2dev
Last active April 1, 2018 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EE2dev/73567318b8c1c9863d0c4d031b2723dd to your computer and use it in GitHub Desktop.
Save EE2dev/73567318b8c1c9863d0c4d031b2723dd to your computer and use it in GitHub Desktop.
Chained transition - text with <span>
license: mit
let containerDiv = "div.chart";
let pathDurations = [];
let app; // the main class in stars.js to create the particles
const explosionStrength = 0.002;
const transitionSpeed = 7;
const starOptions = {
mouseListener: false,
texture: document.querySelector("#star-texture-white"),
frames: createFrames(5, 80, 80),
maxParticles: 2000,
backgroundColor: "#111111",
blendMode: "lighter",
filterBlur: 50,
filterContrast: 300,
useBlurFilter: true,
useContrastFilter: true
}
function displayText(_textArray) {
let sel = d3.select(containerDiv);
// add headers for all strings but the last one
for (let i = 0; i < _textArray.length - 1; i++) {
sel.append("div")
.attr("class", "header h" + i)
.append("h1")
.attr("class", "trans")
.text(_textArray[i]);
}
// add last string by wrapping each letter around a span
// which can be styled individually
let sel2 = sel.append("div")
.attr("class", "header h" + (_textArray.length - 1))
.append("h1")
.attr("class", "trans");
const lastString = _textArray[_textArray.length-1];
for (let i = 0; i < lastString.length; i++) {
sel2.append("span")
.attr("class", "color-" + (i % 5))
.text(lastString[i]);
}
}
function createPaths() {
let bBox = d3.select(containerDiv).node().getBoundingClientRect();
let sel = d3.select(containerDiv)
.append("div")
.attr("class", "paths")
.append("svg")
.attr("width", bBox.width)
.attr("height", bBox.height);
const container = d3.select(containerDiv).node().getBoundingClientRect();
d3.selectAll(containerDiv + " h1")
.each(function(d,i) {
let bBox = d3.select(this).node().getBoundingClientRect();
let xTranslate = d3.select("div.chart").node().getBoundingClientRect().x;
let pos = {};
pos.width = bBox.width;
pos.xStart = xTranslate + (container.width - bBox.width) / 2 - container.x;
pos.yStart = bBox.y + (bBox.height / 2) - container.y;
let p = sel.append("path")
.attr("class", "header hidden trans " + "h" + i)
.attr("d", (d) => {
let str = "M" + pos.xStart + ", " + pos.yStart
+ " L" + (pos.width + pos.xStart) + ", " + pos.yStart;
return str;
});
let duration = p.node().getTotalLength() * transitionSpeed;
pathDurations.push(duration);
});
}
function intializeStars() {
let bBox = d3.select(containerDiv).node().getBoundingClientRect();
d3.select(containerDiv).insert("div", ".h0")
.attr("class", "stars")
.append("canvas")
.attr("id", "view")
.attr("width", bBox.width)
.attr("height", bBox.height);
starOptions.view = document.querySelector("#view");
app = new App(starOptions);
window.addEventListener("load", app.start());
window.focus();
}
function starsAlongPath(path) {
let l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
let p = path.getPointAtLength(t * l);
app.spawn(p.x , p.y);
return "translate(0,0)";
};
};
}
function animateStars() {
let durations = pathDurations.concat(pathDurations);
let chainedSel = d3.selectAll(".trans").data(durations);
chainedTransition(chainedSel);
function chainedTransition(_chainedSel, _index = 0) {
const num_headers = _chainedSel.size() / 2;
let nextSel = _chainedSel.filter((d,i) => (i % num_headers) === _index);
transitionNext(nextSel);
function transitionNext(_selection){
console.log(_index);
if (_index === num_headers - 1) {
setTimeout( function() {
app.setActivate(false); // disable requestAnimationFrame calls
transitionLast(_selection);
}, 1000);
}
else {
// the header
_selection.filter((d,i) => i === 0)
.transition()
.duration(d => d)
.delay(1000)
.ease(d3.easeLinear)
.style("opacity", 1)
// the path
let sel = _selection.filter((d,i) => i === 1);
sel.transition()
.duration(d => d)
.delay(1000)
.ease(d3.easeLinear)
.attrTween("transform", starsAlongPath(sel.node()))
.on ("end", function() {
_index = _index + 1;
if (num_headers > _index) {
nextSel = _chainedSel.filter((d,i) => (i % num_headers) === _index);
transitionNext(nextSel);
}
});
}
}
function transitionLast(_selection){
starOptions.texture = document.querySelector("#star-texture");
let app2 = new App(starOptions);
window.addEventListener("load", app2.start());
window.focus();
// the header
_selection.filter((d,i) => i === 0)
.transition()
.duration(0)
.style("opacity", 1)
// the path
let path = _selection.filter((d,i) => i === 1).node();
let l = path.getTotalLength();
for (let t = 0; t < 1; t = t + explosionStrength) {
let p = path.getPointAtLength(t * l);
app2.spawn(p.x , p.y);
}
setTimeout( function() {
app2.setActivate(false); // disable requestAnimationFrame calls
}, 3000);
}
}
}
let myText = ["My favorite programming language is", "javascript with d3.js"];
displayText(myText);
createPaths();
intializeStars();
animateStars();
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title>stars</title>
<link href="https://fonts.googleapis.com/css?family=Indie+Flower" rel="stylesheet">
<link href="style.css" rel="stylesheet">
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div class="chart"></div>
<aside style="display:none">
<img id="star-texture" src="stars-02.png">
<img id="star-texture-white" src="stars-02w.png">
</aside>
<script src="stars.js"></script>
<script src="animateStars.js"></script>
</body>
</html>
�PNG

IHDR�P7 #�sBIT|d� pHYs  ��~�tEXtSoftwareAdobe Fireworks CS6輲�tEXtCreation Time10/22/17�����IDATx��{�U}�?;D@�G(o�� �+TIL$�%���l�.,P�v�A[ !��(Wl���Z�����)�U�"�ڂD*��$ �$BBHB ��Ǟ�=��{�Ǟ3{Ι�ZY��f�_~3{�={�V"BMMMMMMZF�m@MMMMM5�[@T��6�ʄ����9*����P��7����w��
�-ۈ
��P1�l#*�wTP�/�%�������������U���'���6����i��/ۖ*�f��dS�I�.�./۔��~����lC��_�%�߅u�����: �D_���z(+��� 롬L��[�s�gð�G���\�1�#�>.��N��BR�f���S���t�j60#zw:�GѾ�.΍ޞ�/ќa�S@�����PaE'����� �T���~q��������: IE_���e���
Ocp�RG� g �>����[��̩6�����Y�YH"�<����s���;����_̢: IDs����B����*���G�u��I�����ӈ��ա��TZGʓ���њ�e�"�z,T���}��Q�H�j����s��Y5-2{�97@�m�9��K@�X�pQ����7�}���G3�CUG��0����YȰ�������{�8:c���rE� T�
|h��M����D�fo1g�����a��V�[̹u24j����YQ�� ���K�-���!){�YRg!C���Q3�ƨ�����vFQ�ܐ�w}E�?:b��|�U��4eI}R��7��$�O�Uu�H�Ά�>��Ԫ�H����
P�+Ҟ4�! vlo����^hq�H�}�$�����_L_FT���S_FT�����^]�P���� �� ���,���x������{ 0�R��S��`���p_&U �}�*Ñsв̱5�#�>�p�t��µ=i�!������: �go1}���*I�5�6k�T��Ө�`��3��҈������`-���%tu�#����,$G�3G ��YT1B�����G�e�9{��f�G\ٓ��3��d����d�$�)�����A����[L�#;�J�,����� D����' ��uQt�ț���ja��*�
rgo1ݙ���>b�2 q�}�L5�c��D��g���A�F1y���n��z神�c�U'o��砌*��)�������hl�����* q�}����=Q���#f��'�U�
w�TtyQt� p��Ŝm������2��q'�Ѽ�6�*���sXV�,�����p�wt[�*{�)- n�£��p+ s��q��*\go13���2�Cγ����Bl��2{��,���@�w�i�e&�� �Z�w~�=Q���-�[�(r��5�� ��w�L�d!7�V<��+���7Q�8�y`LA5ttR`�3]K�F�f1S�йQt�N�^E�i��G��"��� J�B�;\uR��d�r�ӊ����=��U�%R6 ���,�Pqp
vKړ�9�{
�r5�_���X?n�B%��������^���|��5ѿ b(y����*���ѿ^`j�5����m��ۈ.{��l���6���gX��X�Z��h(��D��3P$_��>��:ru�_۸Eo*�0�Pq8� ����{����{qj�t���q�l0����E���f-�J /�i�:���6~}@����_����~���u����>�oC_� 򛼅'��?
n���kD��`�� �jD�⪒P��F$'�����Ӣs��fW������N�_cƷX-�-�j ա �[��`g���� ���ř�ԡض�8�����1��[�2ȫI
�@���#^�1�c�����P1�������6���Ѣs������1��d���C9{_��?BuC_����d�x���e-Z�/`����Xdk��>�;�E9zm���)�_ǎ;9��i�\����؍�j��p�VFCPP��p��v ��������lS�x�����`)V(j���5ȦQ��(<�"�>��Z�\ 8��pvWia%�6W��!�g'p����Ej��ap%Z��El��V�U�ap�A6��!�`plY�U���D?��E���2j� �N`��O��8��VU�m����?�� ����t�p_R��Ѓ�@P�`g���k�V���%��D�"r0����OK�EdX�a���~�Q���C� �'���?�"2[� �����ð;l�T㇃ga�e֗��eY؆���_L$"�d0O�0�_D-"C��pX�K�,��_#��^���o(j�!�ZM�E����N��W����Ob�D�a�f�W #v~{�E����=1���`��J<��ZX�73�O�v3��@ ����"�����i�@ k����K+Z�b���
��Jl"�x����'mf��AB�M����4�����t���h)����Ӓ��k@]��m��FB�����i&�L�~`�3��C,��o��x��ؽ�����@ /c��m�܋�1l�G��o0;�xh��L8�x��L�<���#�$Y�݊�,`y~�*��8�-t�of��1�Dw�p,�:��X�&^��+1���u����I~�l?�[�yt��lf���HD�A�7��8��"���']��!뀙��#FK���:l摨�KJ$"� «��1��7�������شW�������"�{ü�E"r����bx��ҵt��ƊG��/ �����4�iw$�"r1v�Nb0�(�i�N�u����"+��D^��B:��X�D^�,J<b +�+��y�^�)����w ��i����QY$"�$�k��Ql�� "?kG}m`0�p�+�v���N�m�ZtQ'�I"�K2�d�݊�|�?2�k��ў���N���v�GL$"�� ��F�s��_D�.¿���c�^\�U< ���~�TWDV3�-1��\L���Mh;b*/R�x�X��/.h�x�4�HUEx90/�d&���ލ��s��~l��p��,ha��G)Q<b"��/�&1Z�*�˱������u�U��a����' �����s�����B,��^�- Y�-[<b�TN��cW�-��ۋ�*��R����#�P9^
,0�.
�/ ���n�⻈,��"1��|�j�o�P[Җ��ʈ�R�|o�#FKUDx)�-��6��HD� ��c�c���_ +ui�>ؽt}�h~
��-ۈV��}����e�҂IZ���<D�v�(ۖ'���B�N���&�tϑh�m�F�"@�>��c�A����B9 ��_�(���e0��x��������/j�{���>��i��sMm_>�(ۀ�ݾS�6`|�����}��.е�87�1��`ߗ}���w����ھ|t]��� ���� �w�|�`|o��_�����m2�<�[w���ݾ����� ���n�z'��� 
�R�#pP�8�l#�"��5�l;F�0pT�F I��N.ی8�PV�C���I&'��\�N@Tx,0�Yy��k�5S� �5H��+ۈ�: 3اl#��NT�F$�i��2�ci�W;}m��:��k`Ќ����vь���ծf��_��k�Ҍ���v5�kG�]��z���������4.��H1��_����6���z^���N_�j��!��4�ɨ�ǧ���)ђ+��k�܌��~U�竝Ui�N�΍�ة��� ��g�MB�h��X��ϖlP�bo�W��T��l�P���D1�*�f��C���T����ds����3�b|�bz�{ �f|���P�D1���*3�b|k���ϑp�?WR���V�����-�/�Al���v�����w������xy���^.�l�:�"��+X��������J@\v���ہI��Klt~-�rg�:@� bp0^ �� �A��7v�7�/��p-������t��7�r-v��p�J'g [���D����"���Y�u% . �|����m��݈���M�q�o �ED�{��-ܠ����S _�3ތ��
|k���w'0Q 7����N1܎m�_�
L^|�@\��]�ױ�ч{�iى�۰�ߗq�?�گ��� �*�c�/�Y�n�[�B�w�������PJ�O��(�X�� �: �<�d�;�m�@D��x�SBų�L! �3Зd��P1����8@ ��x�ST�z�������B���n>웱�7�1bx+��n �F�،G�|�-#��P ,>E��~ہ��.w��N�z��𷀻�[ 2�pi�:��\Cv��j'7�� �
��w��Od��h` ֑�3�}���8�����QY���?n��� �����X�Zx*�qNQyv���I Og��lFw��w��d8�-�:x5��?nB�� ����Yn�O@���sJ���ݧ�8d��yp�=@�Q����$�5.��N"�x����K2����i� ��cOH|F�2�h)0] �f-l��'��� E�2��e�����pY�� b�
�y�[�"|������d-ϣ�Q�?�P�/�_��'0� �"Yk��g�m/v'�s! i�80ѳ����A�ZD 8�t����9���Ы�_��\ k��`*��)�b~��bx�E�bxF �C��������!`6Z.B�cNj��4Z.��8җ���?fd�AwQ�A�2���b�8��\H��d5`�����A���$�?� �#}�I��!<\�G ?.�-<������Mp�/ 8�+��a��a��O s ���" I���%h���4�Tr�<�����G��~���ǁ��e�$m+5y� ����$C�Nگ n
��O���D�K�C�� ����|��k/`�Q�������K�~������
_2���X\ �!���1,�t�R`�0?��õ�u�1��h��-�h� 6�6pj�/S�;�k�g�87a�������U��ԉ���>� �-ع��B��ig�P�4v��P���"z[{�H�x���H����v�ݨ�P1
��蹈��8P ;�nX*`pL��/cm�'1��O��v�} ���1%�d ��A�p pZ��ߨ�P��}��M߾ �AK�3��V�এ7`��=Cy� P�����M_�d�'�D��c���7�_��*���1�)v��'����^D?\�Q�A3��b�] ��/Z��j��;�s�$J� A4� ڊ}��N1�
[#�Z]�`g�5��t��,�* TG2�I�-�W�@�S܁x��Oa��6�o2Z��� %@����-D���������od`�0��o&[�!�x�]Xᘈ�>��@�D���_��Tq���q� ���D-|�'���-|�0����_���0�؇�Ƌ�6��@ ���M���~-���q�x�� l�ރ�۽-��� ��Ƨ����_���x�|�'�0ț�y� 0�_�a���G�^�Do�kL�P������,3B����hᥲ�HK��]�m-�\�*�j��[�T�Q��9`��\�!�� vh�Khq�TP���P�z` Zn/ˌ��ؠ�K�\�i P�co0�y��+ ��vJ�d�C�>Z<y9�b�J�
%����R��������l��(Cu���~7K������t.w$������"�F��e
��oIEND�B`�
�PNG

IHDR�P7 #�bKGD������� pHYs  ��~�tIME����%UIDATx��ܻv�0@Aa����*}��>�Vi"�c�KX����#IҷIR��xď?~�Mȏ?}��/l<7���S���ȏ?~� Ǐ?u� �6���S�b���Ǐ_װ9mN�: 7(?~}��6� 7�M*~R����ǯ��F~�f�Y%��� �_%?���}j�6^�P�����w~���=�؄�4x�g�6?~��M=�H����u�=���Ǐ��$i���_o�� ?~��9�H���]�u�?���Ǐ��$����_��� ?~��}��{O�ˆ�Ǐ�|��Sò�������2�?�,��?~��m���T����Ǐ�(���d$?~����O���La~����o9��Ǐ�8������Ǐ��~��Ǐ?~���m��?~�F��G6?~���� ��m&~���k��~~���k��n~���k�_�^~���k�_�N~���k�_�>~���k�_�.~���k��\?~���� �Ǯ�?~�J��p�5��������������u��wv�TD\���z���1@*!.��g���� ��A �$D�d�H� �tm_vI2@ 6���Ϻ�3J��@$I�$��$ ]�y ?II�o(���]/?~N ��z'I����Kď?~9�
����� ����/�B��e]����+ӄ�Ǐ���^9��/�� ?~������"���n���������w�� ��ȏ?~ ���x7"�|v�����V��9����y��{~Eȩ���wߓ�a�_���?Id?��Ǐ_Y���Eg<>Vyb�Ǐ��~Ws�J�?~�J�]C�2oD~���+�wׯ2�$ ˯s�$�W��
�6�FIEND�B`�
// from https://codepen.io/osublake/pen/RLOzxo by Blake Bowen
// adjusted by some lines
// - to optionally switch off requestAnimationFrame calls after animation is finished
// - to remove options panel
// - to remove mouse listener
console.clear();
var log = console.log.bind(console);
var TAU = Math.PI * 2;
//
// PARTICLE
// ===========================================================================
var Particle = /** @class */ (function () {
function Particle(texture, frame) {
this.texture = texture;
this.frame = frame;
this.alive = false;
this.width = frame.width;
this.height = frame.height;
this.originX = frame.width / 2;
this.originY = frame.height / 2;
}
Particle.prototype.init = function (x, y) {
if (x === void 0) { x = 0; }
if (y === void 0) { y = 0; }
var angle = random(TAU);
var force = random(2, 6);
this.x = x;
this.y = y;
this.alpha = 1;
this.alive = true;
this.theta = angle;
this.vx = Math.sin(angle) * force;
this.vy = Math.cos(angle) * force;
this.rotation = Math.atan2(this.vy, this.vx);
this.drag = random(0.82, 0.97);
this.scale = random(0.1, 1);
this.wander = random(0.5, 1.0);
this.matrix = { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 };
return this;
};
Particle.prototype.update = function () {
var matrix = this.matrix;
this.x += this.vx;
this.y += this.vy;
this.vx *= this.drag;
this.vy *= this.drag;
this.theta += random(-0.5, 0.5) * this.wander;
this.vx += Math.sin(this.theta) * 0.1;
this.vy += Math.cos(this.theta) * 0.1;
this.rotation = Math.atan2(this.vy, this.vx);
this.alpha *= 0.98;
this.scale *= 0.985;
this.alive = this.scale > 0.06 && this.alpha > 0.06;
var cos = Math.cos(this.rotation) * this.scale;
var sin = Math.sin(this.rotation) * this.scale;
matrix.a = cos;
matrix.b = sin;
matrix.c = -sin;
matrix.d = cos;
matrix.tx = this.x - ((this.originX * matrix.a) + (this.originY * matrix.c));
matrix.ty = this.y - ((this.originX * matrix.b) + (this.originY * matrix.d));
return this;
};
Particle.prototype.draw = function (context) {
var m = this.matrix;
var f = this.frame;
context.globalAlpha = this.alpha;
context.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty);
context.drawImage(this.texture, f.x, f.y, f.width, f.height, 0, 0, this.width, this.height);
return this;
};
return Particle;
}());
//
// APP
// ===========================================================================
var App = /** @class */ (function () {
function App(options) {
var _this = this;
this.pool = [];
this.particles = [];
this.pointer = {
x: -9999,
y: -9999
};
this.buffer = document.createElement("canvas");
this.bufferContext = this.buffer.getContext("2d");
this.supportsFilters = (typeof this.bufferContext.filter !== "undefined");
_this.activate = true;
this.setActivate = function(b) {_this.activate = b;} // setter for activate
// this.setTexture = function(t) {_this.texture = t;}
this.AnimationId;
this.pointerMove = function (event) {
event.preventDefault();
var pointer = event.targetTouches ? event.targetTouches[0] : event;
_this.pointer.x = pointer.clientX;
_this.pointer.y = pointer.clientY;
for (var i = 0; i < random(2, 7); i++) {
_this.spawn(_this.pointer.x, _this.pointer.y);
}
};
this.resize = function (event) {
_this.width = _this.buffer.width = _this.view.width; // = window.innerWidth;
_this.height = _this.buffer.height = _this.view.height; // = window.innerHeight;
};
this.render = function (time) {
var context = _this.context;
var particles = _this.particles;
var bufferContext = _this.bufferContext;
context.fillStyle = _this.backgroundColor;
context.fillRect(0, 0, _this.width, _this.height);
bufferContext.globalAlpha = 1;
bufferContext.setTransform(1, 0, 0, 1, 0, 0);
bufferContext.clearRect(0, 0, _this.width, _this.height);
bufferContext.globalCompositeOperation = _this.blendMode;
for (var i = 0; i < particles.length; i++) {
var particle = particles[i];
if (particle.alive) {
particle.update();
}
else {
_this.pool.push(particle);
removeItems(particles, i, 1);
}
}
for (var _i = 0, particles_1 = particles; _i < particles_1.length; _i++) {
var particle = particles_1[_i];
particle.draw(bufferContext);
}
if (_this.supportsFilters) {
if (_this.useBlurFilter) {
context.filter = "blur(" + _this.filterBlur + "px)";
}
context.drawImage(_this.buffer, 0, 0);
if (_this.useContrastFilter) {
context.filter = "drop-shadow(4px 4px 4px rgba(0,0,0,1)) contrast(" + _this.filterContrast + "%)";
}
}
context.drawImage(_this.buffer, 0, 0);
context.filter = "none";
if (_this.activate) { // call requestAnimateFrame just if flag is true
this.AnimationId = requestAnimationFrame(_this.render);
}
else {
cancelAnimationFrame(this.AnimationId);
}
};
Object.assign(this, options);
this.context = this.view.getContext("2d", { alpha: false });
}
App.prototype.spawn = function (x, y) {
var particle;
if (this.particles.length > this.maxParticles) {
particle = this.particles.shift();
}
else if (this.pool.length) {
particle = this.pool.pop();
}
else {
particle = new Particle(this.texture, sample(this.frames));
}
particle.init(x, y);
this.particles.push(particle);
return this;
};
App.prototype.start = function () {
this.resize();
this.render();
this.view.style.visibility = "visible";
if (this.mouseListener) {
if (window.PointerEvent) {
window.addEventListener("pointermove", this.pointerMove);
}
else {
window.addEventListener("mousemove", this.pointerMove);
window.addEventListener("touchmove", this.pointerMove);
}
}
window.addEventListener("resize", this.resize);
requestAnimationFrame(this.render);
return this;
};
return App;
}());
//
// CREATE FRAMES
// ===========================================================================
function createFrames(numFrames, width, height) {
var frames = [];
for (var i = 0; i < numFrames; i++) {
frames.push({
x: width * i,
y: 0,
width: width,
height: height
});
}
return frames;
}
//
// REMOVE ITEMS
// ===========================================================================
function removeItems(array, startIndex, removeCount) {
var length = array.length;
if (startIndex >= length || removeCount === 0) {
return;
}
removeCount = (startIndex + removeCount > length ? length - startIndex : removeCount);
var len = length - removeCount;
for (var i = startIndex; i < len; ++i) {
array[i] = array[i + removeCount];
}
array.length = len;
}
//
// RANDOM
// ===========================================================================
function random(min, max) {
if (max == null) {
max = min;
min = 0;
}
if (min > max) {
var tmp = min;
min = max;
max = tmp;
}
return min + (max - min) * Math.random();
}
function sample(array) {
return array[(Math.random() * array.length) | 0];
}
div.chart {
position: relative;
padding: 30px;
}
div.header {
margin: 0 auto;
text-align: center;
width: max-content;
}
div.paths, div.stars {
position: absolute;
top: 0px;
left: 0px;
z-index: -1;
}
h1 {
color: lightGrey;
opacity: 0;
font-family: 'Indie Flower', cursive;
}
.color-0 { color: rgb(255, 0, 171); }
.color-1 { color: rgb(0, 168, 255); }
.color-2 { color: rgb(171, 0, 255); }
.color-3 { color: rgb(255, 171, 0); }
.color-4 { color: rgb(168, 255, 0); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment