UNPKG

6.92 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var raf = (typeof window !== 'undefined' && window.requestAnimationFrame) || setTimeout;
4var nextFrame = function (fn) { raf(function () { raf(fn); }); };
5function setNextFrame(obj, prop, val) {
6 nextFrame(function () { obj[prop] = val; });
7}
8function getTextNodeRect(textNode) {
9 var rect;
10 if (document.createRange) {
11 var range = document.createRange();
12 range.selectNodeContents(textNode);
13 if (range.getBoundingClientRect) {
14 rect = range.getBoundingClientRect();
15 }
16 }
17 return rect;
18}
19function calcTransformOrigin(isTextNode, textRect, boundingRect) {
20 if (isTextNode) {
21 if (textRect) {
22 //calculate pixels to center of text from left edge of bounding box
23 var relativeCenterX = textRect.left + textRect.width / 2 - boundingRect.left;
24 var relativeCenterY = textRect.top + textRect.height / 2 - boundingRect.top;
25 return relativeCenterX + 'px ' + relativeCenterY + 'px';
26 }
27 }
28 return '0 0'; //top left
29}
30function getTextDx(oldTextRect, newTextRect) {
31 if (oldTextRect && newTextRect) {
32 return ((oldTextRect.left + oldTextRect.width / 2) - (newTextRect.left + newTextRect.width / 2));
33 }
34 return 0;
35}
36function getTextDy(oldTextRect, newTextRect) {
37 if (oldTextRect && newTextRect) {
38 return ((oldTextRect.top + oldTextRect.height / 2) - (newTextRect.top + newTextRect.height / 2));
39 }
40 return 0;
41}
42function isTextElement(elm) {
43 return elm.childNodes.length === 1 && elm.childNodes[0].nodeType === 3;
44}
45var removed, created;
46function pre() {
47 removed = {};
48 created = [];
49}
50function create(oldVnode, vnode) {
51 var hero = vnode.data.hero;
52 if (hero && hero.id) {
53 created.push(hero.id);
54 created.push(vnode);
55 }
56}
57function destroy(vnode) {
58 var hero = vnode.data.hero;
59 if (hero && hero.id) {
60 var elm = vnode.elm;
61 vnode.isTextNode = isTextElement(elm); //is this a text node?
62 vnode.boundingRect = elm.getBoundingClientRect(); //save the bounding rectangle to a new property on the vnode
63 vnode.textRect = vnode.isTextNode ? getTextNodeRect(elm.childNodes[0]) : null; //save bounding rect of inner text node
64 var computedStyle = window.getComputedStyle(elm, void 0); //get current styles (includes inherited properties)
65 vnode.savedStyle = JSON.parse(JSON.stringify(computedStyle)); //save a copy of computed style values
66 removed[hero.id] = vnode;
67 }
68}
69function post() {
70 var i, id, newElm, oldVnode, oldElm, hRatio, wRatio, oldRect, newRect, dx, dy, origTransform, origTransition, newStyle, oldStyle, newComputedStyle, isTextNode, newTextRect, oldTextRect;
71 for (i = 0; i < created.length; i += 2) {
72 id = created[i];
73 newElm = created[i + 1].elm;
74 oldVnode = removed[id];
75 if (oldVnode) {
76 isTextNode = oldVnode.isTextNode && isTextElement(newElm); //Are old & new both text?
77 newStyle = newElm.style;
78 newComputedStyle = window.getComputedStyle(newElm, void 0); //get full computed style for new element
79 oldElm = oldVnode.elm;
80 oldStyle = oldElm.style;
81 //Overall element bounding boxes
82 newRect = newElm.getBoundingClientRect();
83 oldRect = oldVnode.boundingRect; //previously saved bounding rect
84 //Text node bounding boxes & distances
85 if (isTextNode) {
86 newTextRect = getTextNodeRect(newElm.childNodes[0]);
87 oldTextRect = oldVnode.textRect;
88 dx = getTextDx(oldTextRect, newTextRect);
89 dy = getTextDy(oldTextRect, newTextRect);
90 }
91 else {
92 //Calculate distances between old & new positions
93 dx = oldRect.left - newRect.left;
94 dy = oldRect.top - newRect.top;
95 }
96 hRatio = newRect.height / (Math.max(oldRect.height, 1));
97 wRatio = isTextNode ? hRatio : newRect.width / (Math.max(oldRect.width, 1)); //text scales based on hRatio
98 // Animate new element
99 origTransform = newStyle.transform;
100 origTransition = newStyle.transition;
101 if (newComputedStyle.display === 'inline') //inline elements cannot be transformed
102 newStyle.display = 'inline-block'; //this does not appear to have any negative side effects
103 newStyle.transition = origTransition + 'transform 0s';
104 newStyle.transformOrigin = calcTransformOrigin(isTextNode, newTextRect, newRect);
105 newStyle.opacity = '0';
106 newStyle.transform = origTransform + 'translate(' + dx + 'px, ' + dy + 'px) ' +
107 'scale(' + 1 / wRatio + ', ' + 1 / hRatio + ')';
108 setNextFrame(newStyle, 'transition', origTransition);
109 setNextFrame(newStyle, 'transform', origTransform);
110 setNextFrame(newStyle, 'opacity', '1');
111 // Animate old element
112 for (var key in oldVnode.savedStyle) { //re-apply saved inherited properties
113 if (parseInt(key) != key) {
114 var ms = key.substring(0, 2) === 'ms';
115 var moz = key.substring(0, 3) === 'moz';
116 var webkit = key.substring(0, 6) === 'webkit';
117 if (!ms && !moz && !webkit) //ignore prefixed style properties
118 oldStyle[key] = oldVnode.savedStyle[key];
119 }
120 }
121 oldStyle.position = 'absolute';
122 oldStyle.top = oldRect.top + 'px'; //start at existing position
123 oldStyle.left = oldRect.left + 'px';
124 oldStyle.width = oldRect.width + 'px'; //Needed for elements who were sized relative to their parents
125 oldStyle.height = oldRect.height + 'px'; //Needed for elements who were sized relative to their parents
126 oldStyle.margin = '0'; //Margin on hero element leads to incorrect positioning
127 oldStyle.transformOrigin = calcTransformOrigin(isTextNode, oldTextRect, oldRect);
128 oldStyle.transform = '';
129 oldStyle.opacity = '1';
130 document.body.appendChild(oldElm);
131 setNextFrame(oldStyle, 'transform', 'translate(' + -dx + 'px, ' + -dy + 'px) scale(' + wRatio + ', ' + hRatio + ')'); //scale must be on far right for translate to be correct
132 setNextFrame(oldStyle, 'opacity', '0');
133 oldElm.addEventListener('transitionend', function (ev) {
134 if (ev.propertyName === 'transform')
135 document.body.removeChild(ev.target);
136 });
137 }
138 }
139 removed = created = undefined;
140}
141exports.heroModule = { pre: pre, create: create, destroy: destroy, post: post };
142exports.default = exports.heroModule;
143//# sourceMappingURL=hero.js.map
\No newline at end of file