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