- 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