- From: Majid Valipour via GitHub <sysbot+gh@w3.org>
- Date: Mon, 17 Sep 2018 20:12:01 +0000
- To: public-css-archive@w3.org
Here are two examples that showcase how the above AnimationInput construct can be used to create interactive animated effects. ## Gesture Driven Image Resizer In this example we are creating a basic image scale, rotate animation that is linked to corresponding multi-touch gestures using GestureInput. ```html <img id='target'> <script> await CSS.animationWorklet.addModule('scare-rotate-animator.js'); const target = document.getElementById('target'); // Using individual transform properties const rotateEffect = new KeyFrameEffect( target, {rotate: ['rotate(0)', 'rotate(360deg)']}, {duration: 100, fill: 'both' } ); const scaleEffect = new KeyFrameEffect( target, {scale: [0, 100]}, {duration: 100, fill: 'both' } ); // Note the worklet animation has no timeline but two inputs. const animation = new WorkletAnimation( 'image-manipulator', [rotateEffect, scaleEffect], null, {inputs: {'gesture': new GestureInput(target)}} ); animation.play(); </script> ``` ```js registerAnimator('image-manipulator', class { constructor(options) { // Always listen to gestures. this.options.inputs.gesture.listen(this); } animate(currentTime, inputValues, effects) { // Note that currentTime is undefined and unused. // Get current gesture value and update rotation and scale effects accordingly. const {rotate, scale} = inputValues.gesture; effect.children[0].localTime = rotate / 100; effect.children[1].localTime = Math.min(scale, 100); } }); ``` ## Mixing Scroll and Time inputs This example recreates [twitter hidey-bar effect](http://googlechromelabs.github.io/houdini-samples/animation-worklet/twitter-hidey-bar/) that uses two animation input Scroll and Time. The animation is only attached to time input when it is actively animating. So the effect is ```html <div id='scrollingContainer'> <div id='header'>Hidey-bar header</div> <div>Scrolling content</div> </div> <script> await CSS.animationWorklet.addModule('hidey-bar-animator.js'); const $header = document.getElementById('header'); const $scroller = document.getElementById('scrollingContainer'); const headerHeight = .clientHeight; const scrollRange = $scroller.scrollHeight - $scroller.clientHeight; const effect = new KeyFrameEffect($header, [{transform: 'translateY(0)'}, {transform: `translateY(${scrollRange}px)`}], {duration: scrollRange, fill: 'both' }); const scrollInput = new ScrollInput($scroller); const timeInput = document.timeline; // Note the worklet animation has no timeline but two inputs. const animation = new WorkletAnimation('hidey-bar', effect, null, { inputs: {'scroll': scrollInput, 'time': timeInput} data : {'headeHeight': headerHeight} }); animation.play(); </script> ``` ```js const MIN_HIDE_AMOUNT = -50; const MAX_HIDE_AMOUNT = 0; const HIDE_SPEED = 0.35; // hide animation speed in pixel per millisecond function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } function sign(value) { return value < 0 ? -1 : 1; } registerAnimator('hidey-bar', class { constructor(options) { this.scrollInput_ = options.inputs.scroll; this.timeInput_ = options.inputs.time; // Always listen to scroll changes. this.scrollInput_.listen(this); this.headerHeight_ = options.data.headerHeight; this.hideAmount_ = 0; this.lastY_ = -1; this.lastTime_ = 0; this.lastPhase_ = 'idle'; this.lastHideSpeed_ = 1; } animate(currentTime, inputValues, effect) { // Note that currentTime is undefined and unused. // Scroll value is in {x, y, phase} form. const {x, y, phase} = inputValues.scroll; const time = inputValues.time; var currentMinHideAmount = clamp(this.headerHeight_ - y, MIN_HIDE_AMOUNT, 0); if (phase != 'idle') { // When actively scrolling hide in keep with scroll amount. var scrollDelta = this.lastY_ - y; this.lastHideSpeed_ = HIDE_SPEED * sign(scrollDelta) * scrollDelta; this.hideAmount_ += scrollDelta; } else { // When the scroll goes idle we animate based on time // determine if we need to keep sliding the header. bool isCompleted = this.hideAmount_ == currentMinHideAmount || this.hideAmount_ == MAX_HIDE_AMOUNT; bool isStarting = this.lastPhase_ == 'active'; if (isCompleted) { this.timeInput_.unlisten(this); } else { if (isStarting) this.timeInput_.listen(this); // Continue hide/show animation following the direction and speed of last scroll. var timeDelta = time - this.lastTime_; this.hideAmount_ += lastHideSpeed_ * timeDelta; } } this.hideAmount_ = clamp(this.hideAmount_, currentMinHideAmount, MAX_HIDE_AMOUNT); // Position the hidey bar relative to the current scroll amount. effect.localTime = y + this.hideAmount_; this.lastY_ = y; this.lastTime_ = time; this.lastPhase_ = phase; } }); ``` -- GitHub Notification of comment by majido Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/2493#issuecomment-422153926 using your GitHub account
Received on Monday, 17 September 2018 20:12:04 UTC