mirror of https://github.com/sveltejs/svelte
Site: Document svelte/easing (#3292)
parent
c6cd2d43bb
commit
efcd294731
@ -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>
|
@ -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>
|
@ -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
|
||||||
|
/>
|
@ -0,0 +1,43 @@
|
|||||||
|
import * as eases from 'svelte/easing';
|
||||||
|
|
||||||
|
const processed_eases = {};
|
||||||
|
|
||||||
|
for (const ease in eases) {
|
||||||
|
if (ease === "linear") {
|
||||||
|
processed_eases.linear = eases.linear;
|
||||||
|
} else {
|
||||||
|
const name = ease.replace(/In$|InOut$|Out$/, '');
|
||||||
|
const type = ease.match(/In$|InOut$|Out$/)[0];
|
||||||
|
|
||||||
|
if (!(name in processed_eases)) processed_eases[name] = {};
|
||||||
|
processed_eases[name][type] = {};
|
||||||
|
processed_eases[name][type].fn = eases[ease];
|
||||||
|
|
||||||
|
let shape = 'M0 1000';
|
||||||
|
for (let i = 1; i <= 1000; i++) {
|
||||||
|
shape = `${shape} L${(i / 1000) * 1000} ${1000 - eases[ease](i / 1000) * 1000} `;
|
||||||
|
processed_eases[name][type].shape = shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted_eases = new Map([
|
||||||
|
['sine', processed_eases.sine],
|
||||||
|
['quad', processed_eases.quad],
|
||||||
|
['cubic', processed_eases.cubic],
|
||||||
|
['quart', processed_eases.quart],
|
||||||
|
['quint', processed_eases.quint],
|
||||||
|
['expo', processed_eases.expo],
|
||||||
|
['circ', processed_eases.circ],
|
||||||
|
['back', processed_eases.back],
|
||||||
|
['elastic', processed_eases.elastic],
|
||||||
|
['bounce', processed_eases.bounce],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const types = [
|
||||||
|
['Ease In', 'In'],
|
||||||
|
['Ease Out', 'Out'],
|
||||||
|
['Ease In Out', 'InOut']
|
||||||
|
];
|
||||||
|
|
||||||
|
export { sorted_eases as eases };
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Ease Visualiser"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Easing"
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue