一、Snap
1.1 介绍
-
什么是Snap.svg?
-
Snap.svg 是一个专门用于处理SVG的 JavaScript 库 ( 类似jQuery )。
-
Snap 为 Web 开发人员提供了干净、直观、功能强大的API,这些API专门用来操作SVG。
-
Snap 可用于创建动画,操作现有的 SVG 内容,以及生成 SVG 内容。
-
-
为什么选择Snap.svg?
-
Snap 是由 Dmitry Baranovskiy 从零开始编写,专为现代浏览器(IE9 及更高版本、Safari、Chrome、Firefox 和 Opera)而设计。并且Snap可以支持遮罩、剪辑、图案、全渐变、组等功能。
-
Snap 还有一个独特功能是能够与现有的 SVG一起工作。意味着 SVG 内容不必使用 Snap 生成,就可使用 Snap 来处理它。
- 比如可以在 Illustrator 或 Sketch 等工具中创建 SVG 内容,然后使用 Snap 对其进行动画处理和操作。
-
Snap 还支持动画。提供了简单直观的与动画相关的JavaScript API,Snap 可以帮助你的 SVG 内容更具交互性和吸引力
-
Snap.svg 库处理 SVG 就像 jQuery 处理 DOM 一样简单,并且 Snap 是 100% 免费和 100% 开源的。
-
1.2 初体验
-
Snap.svg常用的API:
-
Snap: 工厂函数,创建或获取SVG
- Snap(w, h) 、Snap(selector)….
-
Paper: 纸张 | SVG画布
- circle、rect、line、path、text….
-
Element:元素
- animate、attr、select、before、after…
-
mina:通常用到的一些动画时间函数。
- mina.linear、mina.easeIn、mina.easeOut….
-
-
代码演示
-
绘制一个圆形
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="./libs/snap.svg-min.js"></script> <script> window.onload = function() { // 1.创建一个svg const svg = Snap(300, 300) // svg对象会克隆一份保存在paper中 console.log(svg === svg.paper) // true // 2.在svg画布中绘制一个圆 // const c = svg.circle(100, 100, 50) const c = svg.paper.circle(100, 100, 50) // 3.给圆添加属性 c.attr({ fill: 'blue' }) // 拿到svg的元素对象 // console.log(svg) // 4.将svg添加到body中 document.body.appendChild(svg.node) } </script> </body> </html> -
操作Svg
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg id="svg" width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle1" x="0" y="0" width="100" height="50"></rect> </svg> <script src="./libs/snap.svg-min.js"></script> <script> window.onload = function() { const svg = Snap("#svg") const paper = svg.paper // 绘制一个矩形 const rectangle = paper.rect(0, 100, 100, 50) rectangle.attr({ fill: 'red' }) // 选择已有的矩形进行操作 const rectangle1 = paper.select('#rectangle1') rectangle1.attr({ fill: 'purple' }) } </script> </body> </html>
-
1.3 实现动画
-
基本使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg id="svg" width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle1" x="0" y="0" width="100" height="50"></rect> </svg> <script src="./libs/snap.svg-min.js"></script> <script> window.onload = function() { const svg = Snap("#svg") const paper = svg.paper // 绘制一个矩形 const rectangle = paper.rect(0, 100, 100, 50) rectangle.attr({ fill: 'red' }) // 选择已有的矩形进行操作 const rectangle1 = paper.select('#rectangle1') rectangle1.attr({ fill: 'purple' }) // 实现动画,requestAnimationFrame 1s 61次 // Snap.animate( // 0, // from // 200, // to // function(val) { // console.log('val', val) // // 回调 61 次,将 0-200 拆分成61份 // rectangle1.attr({ // x: val // }) // }, // 1000, // 毫秒 // mina.linear, // function() { // console.log('动画结束了') // } // ) Snap.animate( [0, 0], // from [200, 200], // to function(val) { // console.log('val', val) // 回调 61 次,将 0-200 拆分成61份 rectangle1.attr({ x: val[0], y: val[1] }) }, 3000, // 毫秒 mina.easeout, function() { console.log('动画结束了') } ) } </script> </body> </html> -
鳄鱼动效
- 下面的 SVG 代码有省略(太长了)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <svg version="1.1" id="crocodile" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="375px" height="300px" viewBox="0 0 500 400" enable-background="new 0 0 500 400" xml:space="preserve" > <polyline id="path-eye" opacity="0.25" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" enable-background="new " points=" 121.714,247.568 66.427,193.472 66.427,149.497 " /> <polyline id="path-pie" opacity="0.25" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" enable-background="new " points=" 272.069,237.568 226.782,193.472 226.782,155.497 " /> <polyline id="path-map" opacity="0.25" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" enable-background="new " points=" 412.069,227.568 376.782,193.472 376.782,145.497 " /> <g id="diagram-eye"> <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="238.8165" y1="619.2575" x2="320.3815" y2="700.8225" gradientTransform="matrix(1 0 0 1 -171 -537.5)" > <stop offset="0" style="stop-color: #000000; stop-opacity: 0.15" /> <stop offset="0.9331" style="stop-color: #000000; stop-opacity: 0" /> </linearGradient> <polygon fill="url(#SVGID_2_)" points="91.848,220.855 10.283,139.291 125.35,24.224 206.915,105.789 " /> <rect x="10" y="24.507" fill="#00A99D" width="115.35" height="115.35" /> <path fill="#60C6BA" d="M28.023,82.182c0,0,18.023-28.837,39.652-28.837s39.652,28.837,39.652,28.837s-18.023,28.837-39.652,28.837 S28.023,82.182,28.023,82.182z" /> <g> <circle fill="#9BEADF" cx="67.675" cy="82.182" r="24.031" /> </g> <path fill="#00A99D" d="M67.675,65.017c0,0,3.433,6.866,3.433,17.165s-3.433,17.165-3.433,17.165s-3.433-6.866-3.433-17.165 S67.675,65.017,67.675,65.017z" /> <circle opacity="0.5" fill="#FFFFFF" enable-background="new " cx="57.921" cy="67.48" r="4.806" /> <circle opacity="0.5" fill="#FFFFFF" enable-background="new " cx="50.712" cy="74.689" r="2.403" /> </g> <g id="diagram-pie"> <linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="400.0527" y1="624.0652" x2="473.0262" y2="697.0389" gradientTransform="matrix(1 0 0 1 -171 -537.5)" > <stop offset="0" style="stop-color: #000000; stop-opacity: 0.25" /> <stop offset="0.9" style="stop-color: #000000; stop-opacity: 0" /> </linearGradient> <path fill="url(#SVGID_6_)" d="M272.351,43.267l-86.596,86.597l72.973,72.973l86.596-86.596L272.351,43.267z" /> <circle fill="#60C6BA" cx="226.973" cy="83.304" r="61.828" /> <path fill="#00A99D" d="M197.727,137.784c8.708,4.684,18.665,7.347,29.246,7.347c34.146,0,61.828-27.681,61.828-61.828 s-27.681-61.828-61.828-61.828v59.767L197.727,137.784z" /> <g> <g> <g> <g> <g> <defs> <circle id="SVGID_7_" cx="226.973" cy="83.304" r="61.828" /> </defs> <clipPath id="SVGID_8_"> <use xlink:href="#SVGID_7_" overflow="visible" /> </clipPath> <linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="397.6839" y1="619.334" x2="444.7831" y2="666.433" gradientTransform="matrix(1 0 0 1 -171 -537.5)" > <stop offset="0" style="stop-color: #000000; stop-opacity: 0.25" /> <stop offset="1" style="stop-color: #000000; stop-opacity: 0" /> </linearGradient> <path clip-path="url(#SVGID_8_)" fill="url(#SVGID_9_)" d="M258.189,50.329l-4.726,4.726 c6.853,6.853,11.092,16.321,11.092,26.779c0,20.916-16.955,37.871-37.871,37.871c-10.458,0-19.926-4.239-26.779-11.092 l-4.726,4.726l47.099,47.099l63.009-63.009L258.189,50.329z" /> </g> </g> </g> </g> </g> <path fill="#9BEADF" d="M226.973,83.304V21.476c-9.586,0-18.663,2.183-26.76,6.077L226.973,83.304z" /> <circle fill="#60C6BA" cx="226.973" cy="83.304" r="45.34" /> <path fill="#00A99D" d="M272.313,83.304c0-25.041-20.3-45.34-45.34-45.34v90.681C252.013,128.644,272.313,108.345,272.313,83.304z" /> <path fill="#9BEADF" d="M184.162,68.37l42.811,14.934v-45.34C207.166,37.963,190.337,50.669,184.162,68.37z" /> </g> <g id="diagram-map"> <linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="505.6437" y1="570.8013" x2="608.6902" y2="673.8477" gradientTransform="matrix(1 0 0 1 -171 -537.5)" > <stop offset="0" style="stop-color: #000000; stop-opacity: 0.25" /> <stop offset="1" style="stop-color: #000000; stop-opacity: 0" /> </linearGradient> <polygon fill="url(#SVGID_10_)" points="387.104,186.934 330.897,130.727 334.644,33.301 432.069,29.554 488.276,85.761 " /> <path fill="#60C6BA" d="M435.816,117.612c0,9.313-7.549,16.862-16.862,16.862h-78.69c-9.313,0-16.862-7.549-16.862-16.862v-78.69 c0-9.313,7.549-16.862,16.862-16.862h78.69c9.313,0,16.862,7.549,16.862,16.862V117.612z" /> <g> <path fill="#00A99D" d="M412.875,101.541c-0.173,1.625-0.483,1.955,1.618,1.847C414.559,102.355,414.023,101.464,412.875,101.541 C412.822,102.037,414.083,101.46,412.875,101.541z M425.12,118.865c0.869-1.597-3.166-1.674-3.927-1.848 c0.801-2.307-0.758-1.445-2.301-1.944c-0.981-0.317-2.751-2.095-3.72-2.83c-1.12-0.849-2.495-0.625-3.695-1.162 c-1.639-0.734-1.6-2.245-3.661-2.818c-1.15-0.319-4.17,0.105-4.623-0.454c-0.808-0.996-2.685-0.572-3.697-0.255 c-1.204,0.376-2.472,1.029-3.236,2.068c-0.416,0.566-1.26,2.358-1.168,2.545c0.776-0.172,8.085-5.264,8.085-2.542 c0,1.436,4.053,1.143,4.328,2.108c0.547,1.92,3.575,1.939,5.144,1.819c-0.561,2.424,2.1,3.612,3.927,4.158 c-0.159,0.952-1.499,1.761-1.156,2.771C417.782,120.22,423.477,120.739,425.12,118.865 C425.957,117.328,424.645,119.407,425.12,118.865z M395.784,80.974c2.509,0.069,1.327,2.668,3.205,3.107 c1.935,0.453-0.559,5.006,0.952,6.131c0.372-0.824,0.346-1.347,1.385-1.155c-0.047,1.523-1.881,2.833-0.23,4.158 c0.298,0.492,1.155,0.373,1.155,1.155c0,1.539,2.068,4.913,3.927,5.543c0.575-2.302,1.155-4.685,1.155-6.365 c0-1.209-0.534-4.18-1.617-4.722c0.234-1.168,0.235-0.913,0-1.617c-1.028-0.69-0.525-1.354-0.692-2.311 c-0.154-0.88-0.925-2.092-0.925-3.601c0-0.721-1.258-1.364-0.991-2.097c0.381-1.047,0.734-0.752,0.53-2.386 c-0.003,0.008,1.055-2.113,1.155-2.31c-0.512-1.531,2.031-2.269,2.31-3.927c1.698,0.566,1.654-1.618,2.541-1.618 c0.788,0,0.751-1.144,0.924-1.848c1.387,0.347,1.32-0.378,2.541-0.924c1.275-0.651,2.202-2.903,3.696-3.234 c-0.136-0.579-0.367-1.118-0.692-1.617c0.854,0.015,1.187-0.092,1.617-0.462c-0.15-0.595-0.834-1.288-1.155-1.617 c0.57,0.157,1.109,0.08,1.617-0.231c0.407,1.22,1.495,0.917,2.079,0.001c-0.588-0.451-0.413-0.236-0.923-0.924 c-2.706-0.516-1.321-0.662,0.231-1.616c-0.508-1.524-0.092-1.592-1.791-2.426c-0.48-0.236-0.99-1.303-1.212-1.731 c0.616-0.077,1.232-0.154,1.848-0.231c-0.155-0.74-0.927-1.502-1.387-1.848c0.231,0,0.463,0,0.694,0 c-0.272-0.855-1.376-1.159-1.617-2.079c0.231,0,0.461,0,0.692,0c-0.252-1.762,0.278-1.826,0.693-3.696 c0.709,0.076,0.709-0.463,0-1.617c1.639-0.328,0.885-0.792,2.541-0.462c0.214-0.626-0.062-0.534,0.463-0.923 c0.867,1.135-1.279,2.217-1.617,3.232c0.154,0,0.308,0,0.462,0c-1.142,0.548-1.308,3.691-0.692,4.158 c0.473,0.359,2.247-1.061,1.616,1.155c1.652-0.881,1.439-0.474,1.848-1.848c0.158-0.533,0.368-0.674,0.462-1.387 c0.103-0.818-1.031-2.294-0.924-3.927c0.761,0.339,1.825,1.343,2.773,0.923c1.198-0.58,0.322-2.588,1.848-2.079 c0.399-1.329,0.309-4.388-0.001-4.388c0.589,0,1.487-2.163,2.078-2.541c0.9-0.576,2.577-0.124,3.003-1.387 c1.198-0.054,2.052,0.555,2.54,0.231h0.231c0.197-0.515-0.382-0.574-0.462-0.924h0.231c0.151-0.347,0.186-0.377,0.231-0.923 c0.028,0.006,0.057,0.011,0.085,0.017c-2.69-5.74-8.502-9.725-15.261-9.725h-78.69c-9.313,0-16.862,7.549-16.862,16.862v61.411 c0.458,0.918,1.198,2.159,1.477,2.364c1.681,0.128,2.141,3.274,3.465,4.157c0.577,1.067,0.775,2.05,1.617,3.233 c1.367,0.688,2.337,7.623,1.154,7.623c-1.059,0,1.12,6.006,3.004,6.006c0.52,0,2.246,1.595,2.77,2.077 c0.742,0.577,0.698,1.476,1.617,2.08c0.316,0.204,1.355,0.566,1.847,0.693c3.485,0.901,6.774,5.433,10.857,4.619 c0.077,0.231,0.154,0.462,0.231,0.693c0.995,0.053,0.783,0.142,1.386,0.462v0.134h29.595c0.209-0.462-0.014-0.922,0.199-1.524 c0.298-0.276,1.803-5.585-0.229-5.775c0.296-0.644,0.87-1.52,1.155-1.848c0.112,0.498,0.035,0.96-0.231,1.386 c2.802,0.691,0.126-0.015,0.924,0.692c0.154,0,0.307,0,0.461,0c-0.322-2.284,1.188-4.774,0.654-6.635 c-0.335-1.168,1.194-2.637,1.194-3.528c0-1.734,0.816-2.275-0.924-3.233c-0.694-0.382-1.948-0.727-3.234,0 c-2.284,3.036-5.775,0.71-5.775,6.072c0,1.772-2.141,5.815-3.927,6.167c-0.333-0.267-0.576-0.568-0.693-0.923 c-0.542,0.181-1.804,0.217-2.238,0.526c-0.244,0.173-0.924,1.288-0.996,1.321c-0.92-0.453-2.549,0.335-3.552,0.408 c-1.738,0.126-1.403-2.025-3.031-2.025c-2.078,0-1.885-0.493-2.893-2.494c-0.721-1.432-0.569-2.181-2.075-3.05 c-0.257-0.257-0.254-0.6-0.461-0.924c-0.567-0.888-1.997-2.877-2.079-4.156c-0.198,0.127-0.568,0.36-0.692,0.462 c0.316-1.902,0.693-4.139,0.692-5.775c0-0.996-0.947-2.768-0.678-3.571c0.325-0.972-0.078-2.736-0.015-3.357 c-0.317-1.908,0.494-1.278,0.692-3.004c0.212-0.369,1.095-0.273,1.467-1.403c0.323-0.98,0.135-0.973-0.544-1.138 c0.512-1.53-0.621-1.696-0.924-3.002c-0.274-1.181-0.879-3.683,0.461-3.234c0.399-1.043,0.425-3.002,1.849-3.002 c1.109,0,1.63-0.648,1.385-1.617c1.057-0.677,2.649-0.532,3.464-1.155c0.065-1.455,1.375-1.531,0.925-3.003 c0.285,0.095,1.319,0.703,1.385,0.693c0.705-0.106,2.3-0.59,2.079-1.617c0.962,0.485,1.113-0.14,1.848,0 c0.005,0,2.327,0.773,1.848,0.693c0.46,0.104,0.876-0.271,1.617-0.463c-0.211,1.814,1.416,1.576,2.541,0.923 c0,0.154,0,0.308,0,0.462c-2.585,1.273,2.05,1.263,2.54,1.385c-0.253-0.934-0.693-1.484,0.231-2.309 c0.628,0.173,3.465,2.134,3.465,2.308c0,0.726,0.493,0.553,0.924,0.232c-0.194-0.973-2.545-2.14-0.23-2.541 c-0.047-0.174-0.433-1.023-0.693-0.925c-1.103,0.498-0.558-0.805-2.079-0.231c-0.159-0.163-0.461-0.61-0.692-0.923 c0.769-0.104,1.539-0.104,2.31,0c-0.053-0.479,0.108-0.734,0.484-0.766c0.406-0.116,1.422-0.167,1.364-0.159 c0.818-0.111,2.554,1.765,2.309-0.462c0.154,0,0.308,0,0.462,0c0.353,2.143,1.659,1.379,2.078,0.001 c0.584,1.551,1.801,0.262,3.004,0.462c-0.496,1.646,1.971,1.348,2.541,2.772c0.799,0.348,1.109,0.703,2.078,0.461 c-0.381,0.052,2.847-1.321,2.667-0.991C396.719,81.347,395.595,81.32,395.784,80.974 C398.309,81.043,395.457,81.572,395.784,80.974z M428.351,115.631c0.024-0.304-0.19-0.311-0.461-0.231 C428.152,115.658,427.888,115.498,428.351,115.631z M399.478,112.396c0.78,0.312,0.3,1.138-0.462,1.618 C402.647,115.73,399.785,108.812,399.478,112.396z M434.824,120.714c-0.447-0.188-1.037,0.024-1.386,0.462 c-1.893,0.693-2.513-1.081-4.39-0.694c1.479,1.363,0.753,1.063,1.385,2.772c0.088,0.149,1.346,2.124,0.709,2.146 c-0.981,0.035-2.859-0.336-3.845-0.597c-1.739-0.46-3.358,1.223-1.391,1.38c2.47,0.198,4.858,0.304,7.367,0.304 c1.102-1.774,1.884-3.761,2.265-5.893C435.299,120.634,435.062,120.674,434.824,120.714 C434.377,120.526,435.062,120.674,434.824,120.714z M418.188,125.793c-0.611-1.214-4.706-1.446-5.446-0.186 c-0.362,0.616,5.189,3.353,6.758,1.667C419.879,126.867,418.13,125.748,418.188,125.793 C417.857,125.135,418.525,126.058,418.188,125.793z" /> </g> <linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="548.6378" y1="585.9402" x2="596.8632" y2="634.1658" gradientTransform="matrix(1 0 0 1 -171 -537.5)" > <stop offset="0" style="stop-color: #000000; stop-opacity: 0.25" /> <stop offset="0.7305" style="stop-color: #000000; stop-opacity: 0.0245" /> <stop offset="0.9282" style="stop-color: #000000; stop-opacity: 0" /> </linearGradient> <polygon fill="url(#SVGID_11_)" points="413.91,108.619 377.844,71.522 389.591,36.487 434.519,83.888 " /> <path fill="#9BEADF" d="M391.297,48.623h-0.169c0.508-1.435,0.799-2.971,0.799-4.58c0-7.588-6.151-13.739-13.739-13.739 s-13.739,6.151-13.739,13.739c0,1.608,0.291,3.145,0.799,4.58h-0.169l0.504,0.88c0.395,0.911,0.892,1.764,1.466,2.56l11.14,19.459 l11.14-19.459c0.574-0.796,1.071-1.649,1.466-2.56L391.297,48.623z M373.607,44.043c0-2.529,2.051-4.58,4.58-4.58 s4.58,2.05,4.58,4.58c0,2.529-2.051,4.58-4.58,4.58S373.607,46.572,373.607,44.043z" /> </g> <rect id="hit-eye" x="6.5" y="22.061" opacity="0" fill="#FF0000" width="122.667" height="123.071" /> <rect id="hit-pie" x="165.658" y="22.061" opacity="0" fill="#FF0000" width="122.667" height="123.071" /> <rect id="hit-map" x="316.855" y="22.061" opacity="0" fill="#FF0000" width="122.667" height="123.071" /> </svg> <script src="./libs/snap.svg-min.js"></script> <script> window.onload = function() { const crocodileSvgEl = Snap('#crocodile') const ids = ['eye', 'pie', 'map'] ids.forEach(id => { const diagramEl = Snap.select(`#diagram-${id}`) const iconEl = Snap.select(`#hit-${id}`) iconEl.hover(function() { showIcon(diagramEl) }) }) // 封装动画函数 function showIcon(diagramEl) { Snap.animate( 0.8, 1, function(val) { diagramEl.attr({ transform: `scale(${val})` }) }, 500, mina.bounce, // 抖动效果 function() { console.log('动画结束') } ) } } </script> </body> </html>
二、GSAP
2.1 介绍
-
什么是GSAP
-
GSAP全称是( GreenSock Animation Platform)GreenSock 动画平台。
-
GSAP 是一个强大的 JavaScript 动画库,可让开发人员轻松的制作各种复杂的动画。
-
-
GSAP动画库的特点
-
与Snap.svg不一样,GSAP无论是HTML 元素、还是SVG、或是Vue、React组件的动画,都可以满足你的需求。
-
GSAP的还提供了一些插件,可以用最少的代码创建令人震惊的动画,比如:ScrollTrigger插件和MorphSVG插件。
-
GSAP 的核心是一个高速的属性操纵器,随着时间的推移,它可以极高的准确性更新值。它比 jQuery 快 20 倍!
-
GSAP 使用起来非常灵活,在你想要动画的地方基本都可以使用,并且是零依赖。
-
2.2 初体验
- 移动SVG中的一个矩形
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body, ul { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle" x="0" y="0" width="100" height="50" fill="red"></rect> </svg> <script src="./libs/gsap.min.js"></script> <script> window.onload =function() { // selector( document.querySelectorAll() ) | domEL gsap.to('#rectangle', { x: 200, duration: 2 // 秒 }) } </script> </body> </html>
2.3 补间动画(Tween)
-
GSAP的Tween动画有4种类型:
-
gsap.from(targets | selector, vars)- 元素从from定义的状态过渡到元素当前的状态。-
targets | selector: 需动画的元素对象,支持字符串的选择器 -
vars: 需过度动画的属性和GSAP扩展的duration、ease、transformOrigin、repeat、delay、yoyo、stagger、onComplete 等
-
-
gsap.to(targets | selector, vars)- 元素从当前的状态过渡到to状态。 -
gsap.fromTo(targets | selector, fromVars, toVars)-元素从from定义状态过渡到to定义的状态 -
gsap.set(targets | selector, vars)- 立即设置属性(无过度效果)。- 本质上是一个 duration = 0 的 to 补间动画。
-
-
哪些属性可以设置动画?
-
GSAP几乎可以为任何属性制作动画
- 包括 CSS 属性、元素属性、自定义对象属性。
- 甚至 CSS 变量和复杂的字符串。
- 最常见的动画属性、变换和不透明度等。
-
GSAP还专门给CSS形变(transform)相关属性提供了简写,如下图所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body, ul { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle" onclick="scaleRectangle()" x="100" y="100" width="100" height="100" fill="red"></rect> </svg> <script src="./libs/gsap.min.js"></script> <script> function scaleRectangle() { // 支持数组 // gsap.to(["#rectangle"], { // scale: 0.5, // 1 -> 0.5 // duration: 1 // }) // gsap.from(["#rectangle"], { // scale: 0.3, // 0.3 -> 1 // duration: 1 // }) // gsap.fromTo(["#rectangle"], { // scale: 0, // 0% // // duration: 2 // 默认是0.5,此处可省略 // }, { // scale: 1, // 100% // duration: 2, // repeat: -1 // 重复次数,默认不重复,-1为无限循环 // }) // gsap.to(["#rectangle"], { // scale: 0.5, // 1 -> 0.5 // duration: 1, // // 修改动画的坐标原点 // // transformOrigin: 'center' // // transformOrigin: 'left' // // transformOrigin: 'top' // // transformOrigin: 'right' // // transformOrigin: 'bottom' // }) gsap.to(["#rectangle"], { scale: 0.5, // 1 -> 0.5 duration: 1, transformOrigin: 'center', ease: 'bounce.out' // 默认值 power1.out }) } </script> </body> </html> -
2.4 动画时间线(TimeLine)
-
什么是动画时间线(TimeLine):
-
时间线(TimeLine)是用来创建易于调整、有弹性的动画序列。
-
当我们将补间添加到时间线(Timeline)时,默认情况下,它们会按照添加到时间轴的顺序一个接一个地播放。
-
-
TimeLine的使用步骤:
-
第一步:通过gsap.timeline( vars ) 拿到时间线对象
-
第二步:调用时间线上的 Tween 动画方法,比如:form、to 等。
-
-
案例
-
delay
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body, ul { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle1" onclick="scaleRectangle()" x="0" y="0" width="50" height="50" fill="red"></rect> <rect id="rectangle2" x="100" y="0" width="50" height="50" fill="red"></rect> <rect id="rectangle3" x="200" y="0" width="50" height="50" fill="red"></rect> </svg> <script src="./libs/gsap.min.js"></script> <script> function scaleRectangle() { gsap.to('#rectangle1', { scale: 0.5, duration: 1 }) gsap.to('#rectangle2', { scale: 0.5, duration: 1, delay: 1 }) gsap.to('#rectangle3', { scale: 0.5, duration: 1, delay: 2 }) } </script> </body> </html> -
timeline(推荐)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body, ul { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle1" onclick="scaleRectangle()" x="0" y="0" width="50" height="50" fill="red"></rect> <rect id="rectangle2" x="100" y="0" width="50" height="50" fill="red"></rect> <rect id="rectangle3" x="200" y="0" width="50" height="50" fill="red"></rect> </svg> <script src="./libs/gsap.min.js"></script> <script> function scaleRectangle() { const timeline = gsap.timeline() // 支持链式调用 timeline.to(['#rectangle1', '#rectangle2'], { scale: 0.5, duration: 1 }) // .to('#rectangle2', { // scale: 0.5, // duration: 1 // }) .to('#rectangle3', { scale: 0.5, duration: 1 }) } </script> </body> </html>
-
2.5 滑板车案例
-
使用timeline实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <!-- 滑板车 --> <svg id="scooter" height="512" width="512" viewBox="0 0 512.004 512.004" xmlns="http://www.w3.org/2000/svg" > <path id="footer-block" d="m175.669 463.803c-8.283 0-15-6.716-15-15 0-53.743-43.723-97.467-97.467-97.467-14.622 0-28.673 3.153-41.762 9.371-7.483 3.555-16.432.371-19.986-7.112-3.555-7.482-.37-16.431 7.113-19.985 17.143-8.143 35.525-12.273 54.635-12.273 70.286 0 127.467 57.182 127.467 127.467 0 8.283-6.714 14.999-15 14.999z" fill="#c5e1e6" /> <path id="footboard2" d="m442.768 321.476c-63.027 2.945-113.414 51.086-120.563 112.327h-210.801c-8.285 0-15 6.716-15 15s6.715 15 15 15h224.932c8.285 0 15-6.716 15-15 0-52.162 40.777-94.928 92.832-97.36 8.275-.387 14.67-7.408 14.283-15.684-.387-8.275-7.402-14.684-15.683-14.283z" fill="#008adf" /> <path id="footboard1" d="m442.768 321.476c-63.027 2.945-113.414 51.086-120.563 112.327h-66.204v30h80.335c8.285 0 15-6.716 15-15 0-52.162 40.777-94.928 92.832-97.36 8.275-.387 14.67-7.408 14.283-15.684-.387-8.275-7.402-14.684-15.683-14.283z" fill="#0065a3" /> <path id="scooter-head" d="m448.787 415.604c-7.721 0-14.279-5.923-14.932-13.755l-28.796-345.572c-1.291-15.484-11.852-26.275-20.521-26.275-8.283 0-15-6.716-15-15s6.717-15 15-15c12.9 0 25.295 5.971 34.9 16.811 8.852 9.99 14.361 23.12 15.518 36.972l28.797 345.573c.688 8.256-5.447 15.506-13.703 16.194-.425.035-.847.052-1.263.052z" fill="#8db9c4" /> <circle id="wheel4" cx="63.203" cy="448.803" fill="#c5e1e6" r="48.2" /> <path id="wheel3" d="m63.203 512.002c-34.848 0-63.199-28.351-63.199-63.199 0-34.849 28.352-63.199 63.199-63.199 34.85 0 63.201 28.35 63.201 63.199 0 34.848-28.352 63.199-63.201 63.199zm0-96.398c-18.306 0-33.199 14.893-33.199 33.199 0 18.307 14.894 33.199 33.199 33.199 18.307 0 33.201-14.893 33.201-33.199s-14.895-33.199-33.201-33.199z" fill="#1d4659" /> <circle id="wheel2" cx="448.803" cy="448.803" fill="#8db9c4" r="48.2" /> <g fill="#0e232c"> <path id="wheel1" d="m448.803 512.002c-34.848 0-63.199-28.351-63.199-63.199 0-34.849 28.352-63.199 63.199-63.199 34.85 0 63.201 28.35 63.201 63.199 0 34.848-28.352 63.199-63.201 63.199zm0-96.398c-18.307 0-33.199 14.893-33.199 33.199 0 18.307 14.893 33.199 33.199 33.199 18.307 0 33.201-14.893 33.201-33.199s-14.895-33.199-33.201-33.199z" /> <path id="head-block" d="m352.402.002c-8.283 0-15 6.716-15 15s6.717 15 15 15h32.135v-30h-32.135z" /> </g> </svg> <script src="./libs/gsap.min.js"></script> <script> window.onload = function() { const tl = gsap.timeline({ repeat: 1, //重复一次 // yoyo: true // 反向执行动画 }) // 车轮 tl.from( [ '#wheel1', // begin= 0s '#wheel2', // 0.2 '#wheel3', // 0.4 '#wheel4' // 0.6 ], { scaleX: 0, scaleY: 0, duration: 1, transformOrigin: 'center', ease: 'bounce.out', stagger: 0.2 // 间隔时间 }) // 底座 .from( [ "#footboard1", "#footboard2" ] , { scaleX: 0, duration: 1, transformOrigin: 'left', ease: 'bounce.out', }) // 立柱 .from( [ "#scooter-head" ] , { scaleY: 0, duration: 1, transformOrigin: 'bottom', ease: 'bounce.out', }) // 手把和尾部 .from( [ "#head-block", "#footer-block" ] , { scaleX: 0, duration: 1, transformOrigin: 'right', ease: 'bounce.out', }) } </script> </body> </html> -
效果
三、动画案例
- 补充Svg上的两个方法
-
getTotalLength- SVG路径对象.getTotalLength(),该方法返回用户代理对路径总长度(以用户单位为单位)的计算值
-
getPointAtLength- SVG路径对象.getPointAtLength(len),该方法返回路径上指定距离的点的坐标 len
0~SVGPathElement.getTotalLength()的浮点数, 超出范围会换算成最大值或最小值
- SVG路径对象.getPointAtLength(len),该方法返回路径上指定距离的点的坐标 len
-
3.1 运行轨迹
-
CSS3 实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .three-box { width: 630px; height: 330px; background: url(https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/track.jpg); background-size: 100% 100%; } #loc { animation: move 1.2s linear infinite alternate; } @keyframes move { 0% { y: 30; } 100% { y: 50; } } #linePath1 { stroke-width: 3; stroke-dasharray: 416; animation: linePath1 7s linear infinite; } @keyframes linePath1 { 0% { stroke-dashoffset: 416; } 100% { stroke-dashoffset: 0; } } #linePath2 { stroke-width: 3; stroke-dasharray: 458; animation: linePath2 7s linear infinite; } @keyframes linePath2 { 0% { stroke-dashoffset: -458; } 100% { stroke-dashoffset: 0; } } </style> </head> <body> <div class="box-left three-box"> <svg id="svg" height="400" version="1.1" width="744" xmlns="http://www.w3.org/2000/svg" > <desc>Created with Snap</desc> <defs> <linearGradient x1="100%" y1="40.7087699%" x2="4.9797314%" y2="60.8683027%" id="botLine" > <stop stop-color="#F5533D" stop-opacity="0" offset="0%"></stop> <stop stop-color="#F5533D" offset="44.5180532%"></stop> <stop stop-color="#F5533D" stop-opacity="0" offset="100%"></stop> </linearGradient> <linearGradient y2="58.3724103%" x2="96.9326332%" y1="42.713995%" x1="0%" id="topLine" > <stop offset="0%" stop-opacity="0.09801" stop-color="#F5533D" ></stop> <stop offset="50.3914618%" stop-color="#F5533D"></stop> <stop offset="100%" stop-opacity="0" stop-color="#F5533D"></stop> </linearGradient> </defs> <image id="loc" xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/shouye/redPoint.png" preserveAspectRatio="none" x="345" y="41.230000000000004" width="55" height="74" ></image> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/pillar.png" preserveAspectRatio="none" x="478" y="118" width="3" height="79" ></image> <g transform="matrix(1,0,0,1,170,140)"> <path id="linePath1" d="m-11.20703,177c44.13802,-17.33333 100.54036,-41 169.20703,-71c68.66667,-30 138.1224,-64.91471 208.36719,-104.74414" fill="rgba(0,0,0,0)" transform="matrix(1,0,0,1,-32,-5)" stroke="url(#botLine)" ></path> </g> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/path-qiao.png" preserveAspectRatio="none" x="383" y="151" width="75" height="48" ></image> <g transform="matrix(1,0,0,1,225,105)"> <path id="linePath2" d="m2,2c73.33333,21.17188 140.37374,42.06462 201.12121,62.67823c60.74748,20.61362 136.04041,54.05421 225.87879,100.32177" fill="rgba(0,0,0,0)" transform="matrix(1,0,0,1,-32,-5)" stroke="url(#topLine)" ></path> </g> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/path-lou.png" preserveAspectRatio="none" x="111" y="12" width="198" height="233" ></image> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/pillar.png" preserveAspectRatio="none" x="247" y="182" width="3" height="79" ></image> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/pillar.png" preserveAspectRatio="none" x="330" y="65" width="3" height="79" ></image> </svg> </div> </body> </html>
3.2 导航动画
- 路径动画+帧动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> body { /* border: 1px solid red; */ padding-top: 100px; } .five-box { width: 600px; height: 314px; background: url(https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/service-left-loc.png); background-size: 100% 100%; } .line { transform: translate(50px, 90px); } .line path { stroke-width: 4; stroke-dasharray: 521; stroke-dashoffset: 0; animation: linePath 7s linear infinite; } @keyframes linePath { 0% { stroke-dashoffset: 538; } 100% { stroke-dashoffset: 0; } } #loc1 { animation: move1 1.2s linear infinite alternate; } #c1 { animation: moveC1 1.2s linear infinite alternate; } #c2 { animation: moveC2 1.2s linear infinite alternate; } @keyframes move1 { 0% { y: 80; } 100% { y: 100; } } @keyframes moveC1 { 0% { y: 185; } 100% { y: 230; } } @keyframes moveC2 { 0% { y: 230; } 100% { y: 185; } } #pics { /* 回到原点 */ /* transform: translate(-100px, -100px); */ /* 调整原点在图形中心位置 */ /* transform: translate(-127.5px, -182px); */ /* 路径平移: 50 + 90 */ transform: translate(-77.5px, -170px); } svg { overflow: visible; } </style> </head> <body> <div class="box-left five-box"> <svg height="400" version="1.1" width="744" xmlns="http://www.w3.org/2000/svg" > <desc>Created with Snap</desc> <defs> <linearGradient x1="100%" y1="40.7087699%" x2="4.9797314%" y2="60.8683027%" id="linearGradient-5" > <stop stop-color="#F5533D" stop-opacity="0" offset="0%"></stop> <stop stop-color="#F5533D" offset="44.5180532%"></stop> <stop stop-color="#F5533D" stop-opacity="0" offset="100%"></stop> </linearGradient> </defs> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/projection.png" preserveAspectRatio="none" x="60" y="45" width="466" height="234" ></image> <g id="pics"> <image id="loc1" xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/shouye/redPoint.png" preserveAspectRatio="none" x="100" y="98.82" width="55" height="74" style="opacity: 1" ></image> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/navLight.png" preserveAspectRatio="none" x="113" y="155" width="30" height="107" style="opacity: 1" ></image> <image id="c1" xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/bigCircle.png" preserveAspectRatio="none" x="112" y="195.73" width="32" height="11" style="opacity: 1" ></image> <image id="c2" xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/smCircle.png" preserveAspectRatio="none" x="117" y="214.27" width="21" height="8" style="opacity: 1" ></image> <image xlink:href="https://mapopen-website-wiki.cdn.bcebos.com/index/newIndex/nav-tuo.png" preserveAspectRatio="none" x="115" y="252" width="26" height="11" style="opacity: 1" ></image> </g> <g class="line"> <path id="line-path" d="M0,194.179092 C141.464844,148.340947 237.798177,115.607166 289,95.9777477 C365.802734,66.5336204 453.195733,26 482.349179,1" fill="rgba(0,0,0,0)" stroke="url(#linearGradient-5)" ></path> </g> <animateMotion href="#pics" dur="7s" repeatCount="indefinite"> <mpath href="#line-path" /> </animateMotion> </svg> </div> </body> </html>