UNPKG

@tidepool/viz

Version:

Tidepool data visualization for diabetes device data.

699 lines (302 loc) • 24.3 kB
<!DOCTYPE HTML> <html lang="" > <head> <meta charset="UTF-8"> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <title>GSAP · GitBook</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="description" content=""> <meta name="generator" content="GitBook 3.2.2"> <link rel="stylesheet" href="../../gitbook/style.css"> <link rel="stylesheet" href="../../gitbook/gitbook-plugin-highlight/website.css"> <link rel="stylesheet" href="../../gitbook/gitbook-plugin-search/search.css"> <link rel="stylesheet" href="../../gitbook/gitbook-plugin-fontsettings/website.css"> <meta name="HandheldFriendly" content="true"/> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link rel="apple-touch-icon-precomposed" sizes="152x152" href="../../gitbook/images/apple-touch-icon-precomposed-152.png"> <link rel="shortcut icon" href="../../gitbook/images/favicon.ico" type="image/x-icon"> <link rel="next" href="Moment.html" /> <link rel="prev" href="D3.html" /> </head> <body> <div class="book"> <div class="book-summary"> <div id="book-search-input" role="search"> <input type="text" placeholder="Type to search" /> </div> <nav role="navigation"> <ul class="summary"> <li class="chapter " data-level="1.1" data-path="../../"> <a href="../../"> Introduction </a> </li> <li class="chapter " data-level="1.2" data-path="../StartHere.html"> <a href="../StartHere.html"> @tidepool/viz developer guide </a> <ul class="articles"> <li class="chapter " data-level="1.2.1" data-path="../Background.html"> <a href="../Background.html"> background </a> </li> <li class="chapter " data-level="1.2.2" data-path="../FeatureOverview.html"> <a href="../FeatureOverview.html"> overview of features </a> </li> <li class="chapter " data-level="1.2.3" data-path="../Architecture.html"> <a href="../Architecture.html"> planned architecture </a> </li> <li class="chapter " data-level="1.2.4" data-path="../DirectoryStructure.html"> <a href="../DirectoryStructure.html"> app & directory structure </a> </li> <li class="chapter " data-level="1.2.5" data-path="../CodeStyle.html"> <a href="../CodeStyle.html"> code style </a> </li> </ul> </li> <li class="chapter " data-level="1.3" data-path="../views/"> <a href="../views/"> per-view documentation </a> <ul class="articles"> <li class="chapter " data-level="1.3.1" data-path="../../src/components/settings/"> <a href="../../src/components/settings/"> Device Settings view </a> </li> <li class="chapter " data-level="1.3.2" data-path="../views/Trends.html"> <a href="../views/Trends.html"> Trends view </a> </li> </ul> </li> <li class="chapter " data-level="1.4" data-path="../Storybook.html"> <a href="../Storybook.html"> use of React Storybook </a> </li> <li class="chapter " data-level="1.5" data-path="./"> <a href="./"> usage of dependencies </a> <ul class="articles"> <li class="chapter " data-level="1.5.1" data-path="D3.html"> <a href="D3.html"> D3 </a> </li> <li class="chapter active" data-level="1.5.2" data-path="GSAP.html"> <a href="GSAP.html"> GSAP </a> </li> <li class="chapter " data-level="1.5.3" data-path="Moment.html"> <a href="Moment.html"> Moment </a> </li> <li class="chapter " data-level="1.5.4" data-path="React.html"> <a href="React.html"> React </a> </li> <li class="chapter " data-level="1.5.5" data-path="ReactMotion.html"> <a href="ReactMotion.html"> React Motion </a> </li> <li class="chapter " data-level="1.5.6" data-path="Redux.html"> <a href="Redux.html"> Redux </a> </li> <li class="chapter " data-level="1.5.7" data-path="Webpack.html"> <a href="Webpack.html"> webpack </a> </li> </ul> </li> <li class="chapter " data-level="1.6" data-path="../../src/utils/"> <a href="../../src/utils/"> utilities </a> <ul class="articles"> <li class="chapter " data-level="1.6.1" data-path="../../src/utils/apidocs/"> <a href="../../src/utils/apidocs/"> API docs for utilities </a> <ul class="articles"> <li class="chapter " data-level="1.6.1.1" data-path="../../src/utils/apidocs/basal.html"> <a href="../../src/utils/apidocs/basal.html"> basal </a> </li> <li class="chapter " data-level="1.6.1.2" data-path="../../src/utils/apidocs/bloodglucose.html"> <a href="../../src/utils/apidocs/bloodglucose.html"> blood glucose </a> </li> <li class="chapter " data-level="1.6.1.3" data-path="../../src/utils/apidocs/bolus.html"> <a href="../../src/utils/apidocs/bolus.html"> bolus </a> </li> <li class="chapter " data-level="1.6.1.4" data-path="../../src/utils/apidocs/datetime.html"> <a href="../../src/utils/apidocs/datetime.html"> datetime </a> </li> <li class="chapter " data-level="1.6.1.5" data-path="../../src/utils/apidocs/format.html"> <a href="../../src/utils/apidocs/format.html"> format </a> </li> <li class="chapter " data-level="1.6.1.6" data-path="../../src/utils/apidocs/misc.html"> <a href="../../src/utils/apidocs/misc.html"> misc </a> </li> </ul> </li> </ul> </li> <li class="chapter " data-level="1.7" data-path="../misc/"> <a href="../misc/"> misc </a> <ul class="articles"> <li class="chapter " data-level="1.7.1" data-path="../misc/CommonProps.html"> <a href="../misc/CommonProps.html"> Common props </a> </li> <li class="chapter " data-level="1.7.2" data-path="../misc/Docs.html"> <a href="../misc/Docs.html"> Docs setup & publishing </a> </li> <li class="chapter " data-level="1.7.3" data-path="../misc/TimeRenderingModes.html"> <a href="../misc/TimeRenderingModes.html"> Time-rendering modes </a> </li> </ul> </li> <li class="divider"></li> <li> <a href="https://www.gitbook.com" target="blank" class="gitbook-link"> Published with GitBook </a> </li> </ul> </nav> </div> <div class="book-body"> <div class="body-inner"> <div class="book-header" role="navigation"> <!-- Title --> <h1> <i class="fa fa-circle-o-notch fa-spin"></i> <a href="../.." >GSAP</a> </h1> </div> <div class="page-wrapper" tabindex="-1" role="main"> <div class="page-inner"> <div id="book-search-results"> <div class="search-noresults"> <section class="normal markdown-section"> <h2 id="tidepoolvizs-usage-of-gsap">@tidepool/viz&apos;s usage of GSAP</h2> <p><a href="https://greensock.com/" title="GreenSock.com: GSAP" target="_blank">GSAP (GreenSock Animation Platform)</a> is a powerful library for animating HTML5 documents with JavaScript (largely as an alternative to CSS3). GSAP as a product started with <a href="https://greensock.com/gsap-as" title="GSAP ActionScript" target="_blank">a similar animation library</a> for <a href="https://en.wikipedia.org/wiki/Adobe_Flash" title="Wikipedia: Adobe Flash" target="_blank">Flash</a><sup><a href="#fn_a" id="reffn_a">a</a></sup>. The now more widely used JavaScript library has an extensive and yet still fairly intuitive API that allows for finely-grained control of animations, including an API for sequencing within complex animations that is far over and above what can be accomplished with CSS3&apos;s <code>@keyframes</code>. The library is available in several separate modules (TweenLite, TweenMax, TimelineLite, TimelineMax) to keep file sizes small (choose what you need), and even the combination of TweenMax + TimelineMax is less than 200KB minified (that&apos;s about the size of React + ReactDOM but much less than Angular 2<sup><a href="#fn_b" id="reffn_b">b</a></sup>).</p> <h3 id="&#x1F4DA;-resources">&#x1F4DA; resources</h3> <ul> <li><a href="https://greensock.com/docs/#/HTML5/" title="GSAP Docs" target="_blank">GSAP docs</a></li> <li><a href="https://frontendmasters.com/courses/svg-animation/" title="Frontend Masters: Advanced SVG Animation" target="_blank">Advanced SVG Animation</a>, a Frontend Masters course by Sarah Drasner</li> </ul> <h3 id="&#x1F570;&#xFE0F;-when-we-use-gsap">&#x1F570;&#xFE0F; when we use GSAP</h3> <p>Our first choice for animating with React is <a href="ReactMotion.html">React Motion</a>, but we fall back to GSAP where React Motion&apos;s API doesn&apos;t provide what we need. So far the only circumstance that we&apos;ve needed to pull GSAP in for is a staggered animation on revealing the daily CGM sensor traces via hover over a CGM time-slice segment in the CGM Trends view. This is due to the fact that React Motion&apos;s <code>StaggeredMotion</code> component only serves a subset of stagger animations&#x2014;namely, those in which each value in the stagger is <strong>entirely</strong> dependent on the previous and next values. In the case of a CGM sensor trace for a day, while each value is <em>somewhat</em> dependent on its previous value, CGM values fail the <em>entirely dependent</em> criterion: while blood glucose can&apos;t jump from 68 mg/dL to 345 mg/dL in the space of a single five-minute span of time, all blood glucose values <em>do</em> fall within a certain &quot;delta&quot; of the previous value, though this delta varies (i.e., the previous and next values are <strong>not</strong> entirely dependent on each other).</p> <h3 id="&#x1F35D;-integrating-gsap-with-react">&#x1F35D; integrating GSAP with React</h3> <p>The strategy for using GSAP with React is very similar to the <code>componentDidMount</code> strategy for integrating <a href="D3.html#the-componentdidmount-strategy">React and D3</a> but perhaps a little less offensive to the React purist. Instead of <em>rendering</em> to the DOM in the <code>componentDidMount</code> lifecycle method (<strong>after</strong> React&apos;s render cycle), to integrate GSAP with React we first render the component inside a <code>ReactTransitionGroup</code> container. Then in the <code>componentWillEnter</code> method (which is provided by <code>ReactTransitionGroups</code> and fires at the same point in the React lifecycle as <code>componentDidMount</code>) we simply gather the <a href="https://facebook.github.io/react/docs/refs-and-the-dom.html" title="React docs: Refs and the DOM" target="_blank">references to DOM nodes</a> that have just been rendered by React and then pass them to GSAP as the target(s) for animation. We do the same on exit only inside the <code>componentWillLeave</code> method also provided by <code>ReactTransitionGroup</code>. In this way, we&apos;re only modifying the <em>appearance</em> of DOM nodes via GSAP and not disrupting React&apos;s control of rendering to the DOM. (In addition, since animations are more-or-less a nice-to-have<sup><a href="#fn_c" id="reffn_c">c</a></sup> and not absolutely essential to our data visualization functionality, we don&apos;t write tests around them, and so the difficulty of writing tests around things that happen inside React lifecycle methods does not come into play.)</p> <h3 id="&#x270D;&#xFE0F;-example">&#x270D;&#xFE0F; example</h3> <p>If your React component has rendered a series of SVG <code>&lt;circle&gt;</code>s that you want to reveal in a stagger animation, one-by-one, start with assigning a <code>ref</code> on each <code>&lt;circle&gt;</code> in the <code>render</code> method of the component:</p> <pre><code class="lang-js">render() { <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;a-gaggle-of-circles&quot;</span>&gt;</span> {_.map(data, (d) =&gt; ( <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">{5}</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">{10}</span> <span class="hljs-attr">r</span>=<span class="hljs-string">{5}</span> <span class="hljs-attr">opacity</span>=<span class="hljs-string">{0}</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{(node)</span> =&gt;</span> { this[d.id] = node; }} /&gt; ))} <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span> ); } </span></code></pre> <p>Notice that we also render initially with opacity zero; the trick to this staggered render of <code>&lt;circle&gt;</code>s is to render all the <code>&lt;circle&gt;</code>s at the same time (in the React component&apos;s <code>render</code> method) and then stagger the animation to <em>full</em> opacity in <a href="https://facebook.github.io/react/docs/animation.html#componentwillenter" title="React Animation Add-Ons: componentWillEnter" target="_blank"><code>componentWillEnter</code></a>:</p> <pre><code class="lang-js">componentWillEnter(callback) { <span class="hljs-keyword">const</span> { animationDuration, data } = <span class="hljs-keyword">this</span>.props; <span class="hljs-keyword">const</span> targets = _.map(data, (d) =&gt; (<span class="hljs-keyword">this</span>[d.id])); TweenMax.staggerTo( targets, animationDuration, { opacity: <span class="hljs-number">1</span>, onComplete: callback }, animationDuration / targets.length ); } </code></pre> <p>Also note the callback argument provided to <code>componentWillEnter</code>, which we specify as the <code>onComplete</code> in the <code>TweenMax.staggerTo</code> configuration.</p> <hr> <blockquote id="fn_a"> <sup>a</sup>. Link, of course, for the youngins soon to ask, &quot;What the hell is Flash?&quot; (Also, &#x1F3A9; to @krystophv for pointing out to @jebeck that GSAP <em>was</em> originally a Flash animation library.)<a href="#reffn_a" title="Jump back to footnote [a] in the text."> &#x21A9;</a> </blockquote> <blockquote id="fn_b"> <sup>b</sup>. Source for React + React DOM and Angular 2 sizes: <a href="https://gist.github.com/Restuta/cda69e50a853aa64912d" target="_blank">https://gist.github.com/Restuta/cda69e50a853aa64912d</a><a href="#reffn_b" title="Jump back to footnote [b] in the text."> &#x21A9;</a> </blockquote> <blockquote id="fn_c"> <sup>c</sup>. Though very valuable for <a href="https://css-tricks.com/the-importance-of-context-shifting-in-ux-patterns/" title="CSS Tricks: The Importance of Context-Shifting in UX Patterns" target="_blank">context-shifting</a>, which is arguably even <em>more</em> important in data visualization than general application UX, because context-shifting with data aids in understanding changes and relationships in data, which is often (if not always!) the primary communicative purpose of a data visualization.<a href="#reffn_c" title="Jump back to footnote [c] in the text."> &#x21A9;</a> </blockquote> </section> </div> <div class="search-results"> <div class="has-results"> <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1> <ul class="search-results-list"></ul> </div> <div class="no-results"> <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1> </div> </div> </div> </div> </div> </div> <a href="D3.html" class="navigation navigation-prev " aria-label="Previous page: D3"> <i class="fa fa-angle-left"></i> </a> <a href="Moment.html" class="navigation navigation-next " aria-label="Next page: Moment"> <i class="fa fa-angle-right"></i> </a> </div> <script> var gitbook = gitbook || []; gitbook.push(function() { gitbook.page.hasChanged({"page":{"title":"GSAP","level":"1.5.2","depth":2,"next":{"title":"Moment","level":"1.5.3","depth":2,"path":"docs/deps/Moment.md","ref":"docs/deps/Moment.md","articles":[]},"previous":{"title":"D3","level":"1.5.1","depth":2,"path":"docs/deps/D3.md","ref":"docs/deps/D3.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":[],"pluginsConfig":{"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"docs/deps/GSAP.md","mtime":"2017-05-23T17:51:07.000Z","type":"markdown"},"gitbook":{"version":"3.2.2","time":"2017-05-31T15:26:30.892Z"},"basePath":"../..","book":{"language":""}}); }); </script> </div> <script src="../../gitbook/gitbook.js"></script> <script src="../../gitbook/theme.js"></script> <script src="../../gitbook/gitbook-plugin-search/search-engine.js"></script> <script src="../../gitbook/gitbook-plugin-search/search.js"></script> <script src="../../gitbook/gitbook-plugin-lunr/lunr.min.js"></script> <script src="../../gitbook/gitbook-plugin-lunr/search-lunr.js"></script> <script src="../../gitbook/gitbook-plugin-sharing/buttons.js"></script> <script src="../../gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script> </body> </html>