Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion site/content/docs/03-run-time.md
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,23 @@ You can see a full example on the [animations tutorial](tutorial/animate)

### `svelte/easing`

* TODO could have nice little interactive widgets showing the different functions, maybe
Easing functions specificy the rate of change over time and are useful when working with Svelte's built-in transitions and animations as well as the tweened and spring utilities. `svelte/easing` contains 31 named exports, a `linear` ease and 3 variants of 10 different easing functions: `in`, `out` and `inOut`.

You can explore the various eases using the [ease visualiser](examples#easing) in the [examples section](examples).


| ease | in | out | inOut |
| --- | --- | --- | --- |
| **back** | `backIn` | `backOut` | `backInOut` |
| **bounce** | `bounceIn` | `bounceOut` | `bounceInOut` |
| **circ** | `circIn` | `circOut` | `circInOut` |
| **cubic** | `cubicIn` | `cubicOut` | `cubicInOut` |
| **elastic** | `elasticIn` | `elasticOut` | `elasticInOut` |
| **expo** | `expoIn` | `expoOut` | `expoInOut` |
| **quad** | `quadIn` | `quadOut` | `quadInOut` |
| **quart** | `quartIn` | `quartOut` | `quartInOut` |
| **quint** | `quintIn` | `quintOut` | `quintInOut` |
| **sine** | `sineIn` | `sineOut` | `sineInOut` |


### `svelte/register`
Expand Down
106 changes: 106 additions & 0 deletions site/content/examples/11-easing/00-easing/App.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script>
import { interpolateString as interpolate } from 'd3-interpolate';
import { tweened } from 'svelte/motion';

import Grid from './Grid.svelte';
import Controls from './Controls.svelte';

import { eases, types } from './eases.js';

let current_type = 'In';
let current_ease = 'sine';
let duration = 2000;
let current = eases.get(current_ease)[current_type];
let playing = false;
let width;

const ease_path = tweened(current.shape, { interpolate });
const time = tweened(0);
const value = tweened(1000);

async function runAnimations() {
playing = true;

value.set(1000, {duration: 0});
time.set(0, {duration: 0});

await ease_path.set(current.shape);
await Promise.all([
time.set(1000, {duration, easing: x => x}),
value.set(0, {duration, easing: current.fn})
]);

playing = false;
}

$: current = eases.get(current_ease)[current_type];
$: current && runAnimations();
</script>

<style>
.easing-vis {
display: flex;
max-height: 95%;
max-width: 800px;
margin: auto;
padding: 10px;
border: 1px solid #333;
border-radius: 2px;
padding: 20px;
}

svg {
width: 100%;
margin: 0 20px 0 0;
}

.graph {
transform: translate(200px,400px)
}

@media (max-width:600px) {
.easing-vis {
flex-direction: column;
max-height: calc(100% - 3rem);
}
}
</style>

<div bind:offsetWidth={width} class="easing-vis">
<svg viewBox="0 0 1400 1802">
<g class="canvas">
<Grid x={$time} y={$value}/>
<g class="graph">
<path
d={$ease_path}
stroke="#333"
stroke-width="2"
fill="none"
/>

<path d="M0,23.647C0,22.41 27.014,0.407 28.496,0.025C29.978,-0.357 69.188,3.744 70.104,4.744C71.02,5.745 71.02,41.499 70.104,42.5C69.188,43.501 29.978,47.601 28.496,47.219C27.014,46.837 0,24.884 0,23.647Z"
fill="#ff3e00"
style="transform: translate(1060px, {($value - 24)}px)"
/>

<circle
cx="{$time}"
cy="{$value}"
r="15"
fill="#ff3e00"
/>
</g>
</g>
</svg>

<Controls
{eases}
{types}
{playing}
{width}
bind:duration
bind:current_ease
bind:current_type
on:play={runAnimations}
/>
</div>
186 changes: 186 additions & 0 deletions site/content/examples/11-easing/00-easing/Controls.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<script>
import { createEventDispatcher } from 'svelte';

export let current_ease;
export let current_type;
export let eases;
export let types;
export let duration;
export let playing;
export let width;

const dispatch = createEventDispatcher();

$: mobile = width && width < 600;
</script>

<style>
.easing-sidebar {
width: 11em;
}

ul {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
font-size: 18px;
}

li {
padding: 5px 10px;
background: #eee;
border-radius: 2px;
margin: 3px 0;
cursor:pointer;
}

li:hover {
background: #676778;
color: white;
}

.selected {
background: #ff3e00;
color: white;
}

h3 {
margin: 0 10px 0 0;
}

h4 {
margin-bottom: 0;
}

select {
display: inline;
padding: 0.2em;
margin: 0;
}

.duration {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
}

.duration span {
display: flex;
}

.duration input {
width: 80px;
margin: 10px 10px 10px 0 ;
}

.duration button {
margin: 10px 5px;
}

.duration .number {
width: 30px;
}

.duration .play {
margin: 0 5px 0 auto;
width: 100%;
}

@media (max-width:600px) {
.easing-types {
display: flex;
align-items: center;
margin-top: 10px;
}

.easing-sidebar {
width: 100%;
}

.duration .play {
margin-left: auto;
width: unset;
}

h3 {
font-size: 0.9em;
display: inline;
}

h3:nth-of-type(2) {
margin-left: auto;
}

ul li {
margin-right: 10px;
}
}
</style>

<div class="easing-sidebar">
<div class="easing-types">
<h3>Ease</h3>
{#if mobile}
<select bind:value={current_ease}>
{#each [...eases] as [name]}
<option
value={name}
class:selected={name === current_ease}
>
{name}
</option>
{/each}
</select>
{:else}
<ul>
{#each [...eases] as [name]}
<li
class:selected={name === current_ease}
on:click={() => current_ease = name}
>
{name}
</li>
{/each}
</ul>
{/if}
<h3>Type</h3>
{#if mobile }
<select bind:value={current_type}>
{#each types as [name, type]}
<option
value={type}
>
{name}
</option>
{/each}
</select>
{:else}
<ul>
{#each types as [name, type]}
<li
class:selected={type === current_type}
on:click={() => current_type = type}
>
{name}
</li>
{/each}
</ul>
{/if}
</div>
<h4>
Duration
</h4>
<div class="duration">
<span>
<input type="number" bind:value={duration} min="0" step="100"/>
<button class="number" on:click={() => duration -= 100}>-</button>
<button class="number" on:click={() => duration += 100}>+</button>
</span>
<button class="play" on:click={() => dispatch('play')}>
{playing ? 'Restart' : 'Play'}
</button>
</div>
</div>
62 changes: 62 additions & 0 deletions site/content/examples/11-easing/00-easing/Grid.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script>
export let x, y;
</script>

<style>
.grid-line {
stroke:#ccc;
opacity: 0.5;
stroke-width: 2;
}

.grid-line-xy {
stroke: tomato;
stroke-width: 2;
}
</style>

<svelte:options namespace="svg" />

<rect
x=0
y=0
width=1400
height=1800
stroke=#ccc
style="opacity: 0.5"
fill=none
stroke-width=2
/>

{#each { length: 8 } as _, i}
{#if i < 6}
<path
d="M{(i+1) * 200} 0 L{(i+1)*200} 1802"
class="grid-line"
/>
{/if}
<path
d="M0 {(i+1) * 200} L1400 {(i+1)*200} "
class="grid-line"
/>
{/each}

<path
style="transform: translateX({x+200}px)"
d="M0 0 L0 1800"
class="grid-line-xy"
/>
<path
style="transform: translateY({y}px)"
d="M0 400 L1400 400"
class="grid-line-xy"
/>
<rect
x=200
y=400
width=1000
height=1000
stroke=#999
fill=none
stroke-width=2
/>
Loading