复杂的缓动教程
对于更复杂的动画,您可以使用 GreenSock Konva 插件。GreenSock 的缓动比 Konva 内置的缓动更强大。
此演示展示了如何使用 GreenSock 缓动 fillLinearGradientColorStops
属性。
说明:点击形状以开始复杂的带渐变变化的动画。
- Vanilla
- React
- Vue
import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; const stage = new Konva.Stage({ container: 'container', width: width, height: height, }); const layer = new Konva.Layer(); const circle = new Konva.Circle({ x: width / 2, y: height / 2, radius: 70, fillLinearGradientStartPoint: { x: -50, y: -50 }, fillLinearGradientEndPoint: { x: 50, y: 50 }, fillLinearGradientColorStops: [0, 'red', 1, 'yellow'], stroke: 'black', strokeWidth: 4, draggable: true, }); layer.add(circle); stage.add(layer); circle.on('click tap', () => { // 使用常规 Konva 缓动 const tween = new Konva.Tween({ node: circle, duration: 1, scaleX: 1.5, scaleY: 1.5, easing: Konva.Easings.EaseInOut, onFinish: () => { // 通过另一个缓动缩放回去 const tween2 = new Konva.Tween({ node: circle, duration: 1, scaleX: 1, scaleY: 1, easing: Konva.Easings.BounceEaseOut, }); tween2.play(); }, }); tween.play(); // 手动更新渐变 let ratio = 0; const anim = new Konva.Animation((frame) => { ratio += frame.timeDiff / 1000; if (ratio > 1) { ratio = 0; } circle.fillLinearGradientColorStops([ 0, '红色', ratio, '黄色', 1, '蓝色', ]); }, layer); anim.start(); setTimeout(() => anim.stop(), 2000); });
import { Stage, Layer, Circle } from 'react-konva'; import { useRef } from 'react'; const App = () => { const circleRef = useRef(); const handleClick = () => { const circle = circleRef.current; // 使用常规 Konva 缓动 const tween = new Konva.Tween({ node: circle, duration: 1, scaleX: 1.5, scaleY: 1.5, easing: Konva.Easings.EaseInOut, onFinish: () => { // 通过另一个缓动缩放回去 const tween2 = new Konva.Tween({ node: circle, duration: 1, scaleX: 1, scaleY: 1, easing: Konva.Easings.Bounce.EaseOut, }); tween2.play(); }, }); tween.play(); // 手动更新渐变 let ratio = 0; const anim = new Konva.Animation((frame) => { ratio += frame.timeDiff / 1000; if (ratio > 1) { ratio = 0; } circle.fillLinearGradientColorStops([ 0, '红色', ratio, '黄色', 1, '蓝色', ]); }, circle.getLayer()); anim.start(); setTimeout(() => anim.stop(), 2000); }; return ( <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> <Circle ref={circleRef} x={window.innerWidth / 2} y={window.innerHeight / 2} radius={70} fillLinearGradientStartPoint={{ x: -50, y: -50 }} fillLinearGradientEndPoint={{ x: 50, y: 50 }} fillLinearGradientColorStops={[0, '红色', 1, '黄色']} stroke="黑色" strokeWidth={4} draggable onClick={handleClick} onTap={handleClick} /> </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageSize"> <v-layer ref="layerRef"> <v-circle :config="circleConfig" @click="handleClick" @tap="handleClick" ref="circleRef" /> </v-layer> </v-stage> </template> <script setup> import { ref } from 'vue'; import Konva from 'konva'; const stageSize = { width: window.innerWidth, height: window.innerHeight }; const circleConfig = { x: window.innerWidth / 2, y: window.innerHeight / 2, radius: 70, fillLinearGradientStartPoint: { x: -50, y: -50 }, fillLinearGradientEndPoint: { x: 50, y: 50 }, fillLinearGradientColorStops: [0, '红色', 1, '黄色'], stroke: '黑色', strokeWidth: 4, draggable: true }; const circleRef = ref(null); const layerRef = ref(null); const handleClick = () => { const circle = circleRef.value.getNode(); // 使用常规 Konva 缓动 const tween = new Konva.Tween({ node: circle, duration: 1, scaleX: 1.5, scaleY: 1.5, easing: Konva.Easings.EaseInOut, onFinish: () => { // 通过另一个缓动缩放回去 const tween2 = new Konva.Tween({ node: circle, duration: 1, scaleX: 1, scaleY: 1, easing: Konva.Easings.Bounce.EaseOut, }); tween2.play(); }, }); tween.play(); // 手动更新渐变 let ratio = 0; const anim = new Konva.Animation((frame) => { ratio += frame.timeDiff / 1000; if (ratio > 1) { ratio = 0; } circle.fillLinearGradientColorStops([ 0, '红色', ratio, '黄色', 1, '蓝色', ]); }, layerRef.value.getNode()); anim.start(); setTimeout(() => anim.stop(), 2000); }; </script>