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