WangShuXian6 / blog

FE-BLOG
https://wangshuxian6.github.io/blog/
MIT License
45 stars 10 forks source link

SVG #71

Open WangShuXian6 opened 5 years ago

WangShuXian6 commented 5 years ago

SVG

stroke*:定义笔触的颜色。例如:stroke="green"

stroke-dasharray*:定义 dash 和 gap 的长度。它主要是通过使用 , 来分隔 实线 和 间隔 的值。例如:>stroke-dasharray="5, 5" 表示,按照 实线为 5,间隔为 5 的排布重复下去。 stroke-dasharray 并不局限于只能设置两个值,要知道,它本身的含义是设置最小重复单元,即,dash,gap,dash,gap...。比如,我定义 stroke-dasharray="15, 10, 5" 则相当于,[15,10,5] 为一段

stroke-dashoffset*: 用来设置 dasharray 定义其实 dash 线条开始的位置。值可以为 number || percentage。百分数是相对于 SVG 的 viewport。通常结合 dasharray 可以实现线条的运动。

stroke-linecap: 线条的端点样式。

stroke-linejoin: 线条连接的样式

stroke-miterlimit: 一个比较复杂的概念,如果我们只是画一些一般的线段,使用上面 linejoin 即可。如果涉及对边角要求比较高的,则可以使用该属性进行定义。它的值,其实就是角长度比上线宽:

WangShuXian6 commented 5 years ago

使用


<?xml version="1.0" encoding="UTF-8" ?>
<!--XML Name Space:命名空间,指定当前标签用于何种语境-->
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
<rect width="100" height="50"></rect>
</svg>
![svg](https://user-images.githubusercontent.com/30850497/54582613-5bd27580-4a4c-11e9-9f74-33a6f9565315.jpg)

***
>HTML5之前使用SVG的方法
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h3>HTML5之前使用SVG的方法</h3>
<img src="4.svg">
<hr/>
<iframe src="4.svg"></iframe>
<hr/>
<object data="4.svg"></object>
<hr/>
<embed src="4.svg">
</body>
</html>

HTML5之后使用SVG的方法

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h3>HTML5之后使用SVG的方法</h3>
<svg width="600" height="400">
<rect width="300" height="200"></rect>
<rect width="300" height="200" x="300" y="200"></rect>
</svg>
</body>
</html>

WangShuXian6 commented 5 years ago

使用SVG绘图——矩形


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
text-align: center;
}
svg {
  background: #f0f0f0;
}

#r4 {
  /*background: #00f;*/
  /*border: 5px solid #00f;*/
  fill: #00f;
  fill-opacity: .3;
  stroke: #00f;
  stroke-width: 5px;
}

使用SVG绘图——矩形

![svg2-1](https://user-images.githubusercontent.com/30850497/54582668-90dec800-4a4c-11e9-8360-a6806f9b572a.jpg)

***
>svg动画
```html
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——矩形</h3>
<svg width="600" height="400">
  <rect id="r1" width="100" height="80" x="0" fill="rgb(0,0,0)"></rect>
</svg>
<script>
  var r = 0; //红色
  var timer = setInterval(function () {
    var x = r1.getAttribute('x');
    x = parseInt(x);
    x += 10;
    r1.setAttribute('x', x);
    r += 15;
    r1.setAttribute('fill', `rgb(${r},0,0`);
  }, 100)
</script>
</body>
</html>

Kapture 2019-03-19 at 13 59 18



<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
text-align: center;
}
svg {
  background: #f0f0f0;
}

使用SVG绘图——矩形

![svg2-2-4](https://user-images.githubusercontent.com/30850497/54583628-b9b48c80-4a4f-11e9-84d0-edf1d613e3d1.jpg)
***
>动态创建的SVG元素,必须指定所在的XMLNS
```html
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——矩形</h3>
<svg width="600" height="400" id="svg10">
</svg>
<script>
  var data = [
    {"label": "1月", "value": 250},
    {"label": "2月", "value": 200},
    {"label": "3月", "value": 350},
    {"label": "4月", "value": 280}
  ];
  for (var i = 0; i < data.length; i++) {
    var d = data[i];
//动态创建的SVG元素,必须指定所在的XMLNS
//var rect = document.createElement('rect');
    var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
    rect.setAttribute('width', 50);
    rect.setAttribute('height', d.value);
    rect.setAttribute('x', i * 80);
    rect.setAttribute('y', 10);
    svg10.appendChild(rect);
  }
</script>
</body>
</html>

svg2-2-4

WangShuXian6 commented 5 years ago

使用SVG绘图——圆形

hover动画


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
text-align: center;
}
svg {
  background: #f0f0f0;
}

使用SVG绘图——圆形

![Kapture 2019-03-19 at 14 07 44](https://user-images.githubusercontent.com/30850497/54583832-6c84ea80-4a50-11e9-8cfe-8018d3e6acd4.gif)

***

>点击动画
```html
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——圆形</h3>
<svg width="600" height="400" id="svg12">
</svg>
<script>
  //动态添加30个圆形
  for (var i = 0; i < 30; i++) {
    var c = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
    c.setAttribute('r', rn(5, 100));
    c.setAttribute('cx', rn(0, 600));
    c.setAttribute('cy', rn(0, 400));
    c.setAttribute('fill', rc(0, 256));
    c.setAttribute('fill-opacity', Math.random());
    svg12.appendChild(c);
  }
  //使用事件代理方式为每个圆形绑定单击监听函数
  svg12.onclick = function (e) {
    var target = e.target; //事件源对象
//if(target.nodeName==='CIRCLE'){
    if (target.nodeName === 'circle') {
      var timer = setInterval(function () {
//让半径变大
        var r = target.getAttribute('r');
        r = parseFloat(r);
        r *= 1.1;
        target.setAttribute('r', r);
//让透明度变小
        var p = target.getAttribute('fill-opacity');
        p = parseFloat(p);
        p *= 0.8;
        target.setAttribute('fill-opacity', p);
        if (p < 0.001) { //几乎看不见时,删除元素
          clearInterval(timer);
          svg12.removeChild(target);
        }
      }, 50);
    }
  }

  /**random number: 生成指定范围内的随机整数**/
  function rn(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
  }

  /**random color: 生成指定范围内的随机颜色**/
  function rc(min, max) {
    var r = rn(min, max);
    var g = rn(min, max);
    var b = rn(min, max);
    return `rgb(${r},${g},${b})`;
  }
</script>
</body>
</html>

Kapture 2019-03-19 at 14 10 03

WangShuXian6 commented 5 years ago

使用SVG绘图——椭圆

hover 动画


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
text-align: center;
}
svg {
  background: #f0f0f0;
}

使用SVG绘图——椭圆


![Kapture 2019-03-19 at 14 13 38](https://user-images.githubusercontent.com/30850497/54584069-372ccc80-4a51-11e9-9c45-1bb3994a2947.gif)
WangShuXian6 commented 5 years ago

使用SVG绘图——直线


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
text-align: center;
}
svg {
background: #f0f0f0;
}
</style>
</head>
<body>
<h3>使用SVG绘图——直线</h3>
<svg width="600" height="400" id="svg12">
<line x1="0" y1="0" x2="600" y2="400" stroke="#f00" stroke-width="10"></line>
</svg>
<script>
</script>
</body>
</html>
![svg2-6-1](https://user-images.githubusercontent.com/30850497/54584137-70fdd300-4a51-11e9-9166-836019027427.jpg)

***
>
```html
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——直线</h3>
<svg width="600" height="400" id="svg15">
  <!--group: 小组-->
  <g stroke="#800" stroke-width="60">
    <line x1="100" y1="100" x2="200" y2="100"></line>
    <line x1="250" y1="100" x2="500" y2="100"></line>
    <line x1="100" y1="200" x2="200" y2="200"></line>
    <line x1="250" y1="200" x2="500" y2="200"></line>
    <line x1="100" y1="300" x2="200" y2="300"></line>
    <line x1="250" y1="300" x2="500" y2="300"></line>
  </g>
</svg>
<script>
</script>
</body>
</html>

svg2-6-2


WangShuXian6 commented 5 years ago

使用SVG绘图——折线

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——折线</h3>
<svg width="600" height="400" id="svg15">
  <polyline points="50,100 100,200 150,50 200,350 250,200 300,250" stroke="#000" fill-opacity="0"></polyline>
</svg>
<script>
</script>
</body>
</html>

svg2-6-3

WangShuXian6 commented 5 years ago

使用SVG绘图——多边形


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
text-align: center;
}
svg {
  background: #f0f0f0;
}

使用SVG绘图——多边形


![svg2-7-1](https://user-images.githubusercontent.com/30850497/54584422-48c2a400-4a52-11e9-861d-f1d0779451ed.jpg)

***

>
```html
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——多边形</h3>
<svg width="600" height="400" id="svg15">
  <g fill="#008">
    <polygon points="100,100 300,200 500,100"></polygon>
    <polygon points="100,150 100,300 500,300 500,150 300,250"></polygon>
  </g>
</svg>
<script>
</script>
</body>
</html>

svg2-7-2


WangShuXian6 commented 5 years ago

使用SVG绘图——文本

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——文本</h3>
<svg width="600" height="400" id="svg15">
  <!--<span>一段文本</span>-->
  <!--<p>一个段落</p>-->
  <text alignment-baseline="before-edge" font-size="40" x="100" y="100">达内科技 ® 2016</text>
</svg>
<script>
</script>
</body>
</html>

svg2-8

WangShuXian6 commented 5 years ago

使用SVG绘图——图像

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——图像</h3>
<svg width="600" height="400" id="svg15">
  <!--<img src="img/disc.png">-->
  <image xlink:href="img/disc.png" width="400" height="200"></image>
</svg>
<script>
</script>
</body>
</html>

svg2-9

WangShuXian6 commented 5 years ago

使用SVG绘图——渐变对象

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>使用SVG绘图——渐变对象</h3>
<svg width="600" height="400" id="svg15">
  <!--渐变属于特效,必须声明在“特效列表”-->
  <defs>
    <linearGradient id="g1" x1="0" y1="0" x2="100%" y2="0">
      <stop offset="0" stop-color="#f00"></stop>
      <stop offset="50%" stop-color="#ff0"></stop>
      <stop offset="100%" stop-color="#0f0"></stop>
    </linearGradient>
    <linearGradient id="g2" x1="0" y1="0" x2="100%" y2="0">
      <stop offset="0" stop-color="red"></stop>
      <stop offset="17%" stop-color="orange"></stop>
      <stop offset="33%" stop-color="yellow"></stop>
      <stop offset="50%" stop-color="green"></stop>
      <stop offset="67%" stop-color="blue"></stop>
      <stop offset="83%" stop-color="cyan"></stop>
      <stop offset="100%" stop-color="purple"></stop>
    </linearGradient>
  </defs>
  <rect width="500" height="100" x="50" y="50" fill="url(#g1)"></rect>
  <text y="300" font-size="50" fill="url(#g2)">渐变绘图svg</text>
</svg>
<script>
</script>
</body>
</html>

svg2-10

WangShuXian6 commented 5 years ago

SVG绘图——各阶段课程难度系数

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>SVG绘图——各阶段课程难度系数</h3>
<svg id="s1">
  <!--所有的特效对象-->
  <defs id="effectList">
    <!--<linearGradient id="g0" x1="0" y1="0" x2="0" y2="100%">
    <stop offset="0" stop-color="#f00"></stop>
    <stop offset="100%" stop-color="#f00" stop-opacity="0"></stop>
    </linearGradient>-->
  </defs>
  <!--坐标轴小组-->
  <g stroke="#555" stroke-width="2">
    <!--X轴-->
    <line x1="50" y1="450" x2="650" y2="450"></line>
    <line x1="630" y1="440" x2="650" y2="450"></line>
    <line x1="630" y1="460" x2="650" y2="450"></line>
    <!--Y轴-->
    <line x1="50" y1="450" x2="50" y2="50"></line>
    <line x1="40" y1="70" x2="50" y2="50"></line>
    <line x1="60" y1="70" x2="50" y2="50"></line>
  </g>
</svg>
<script>
  var w = 600 + 100;
  var h = 10 * 40 + 100;//难度值*40高度倍率+双倍PADDING
  s1.setAttribute('width', w);
  s1.setAttribute('height', h);
  var data = [
    {label: 'HTML', value: 3},
    {label: 'CSS', value: 5},
    {label: 'JS', value: 7},
    {label: 'DOM', value: 6},
    {label: 'jQuery', value: 5.5},
    {label: 'AJAX', value: 8},
    {label: 'HTML5', value: 6}
  ];
  var colWidth = 600 / (2 * data.length + 1);
  for (var i = 0; i < data.length; i++) {
    var d = data[i]; //遍历每个数据对象
    var cw = colWidth; //柱子的宽
    var ch = d.value * 40; //柱子的高
    var x = (2 * i + 1) * colWidth + 50;
    var y = 500 - 50 - ch;
//动态添加渐变对象
    var c = rc(); //渐变颜色
    var html = `
<linearGradient id="g${i}" x1="0" y1="0" x2="0" y2="100%">
<stop offset="0" stop-color="${c}"></stop>
<stop offset="100%" stop-color="${c}" stop-opacity="0"></stop>
</linearGradient>
`;
    effectList.innerHTML += html;
//动态创建矩形
    var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
    rect.setAttribute('width', cw);
    rect.setAttribute('height', ch);
    rect.setAttribute('x', x);
    rect.setAttribute('y', y);
    rect.setAttribute('fill', `url(#g${i})`);
    s1.appendChild(rect);
  }

  //random color
  function rc() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    return `rgb(${r}, ${g}, ${b})`;
  }
</script>
</body>
</html>

svg2-11

WangShuXian6 commented 5 years ago

SVG绘图——滤镜——高斯模糊滤镜

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }

    svg {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>SVG绘图——滤镜——高斯模糊滤镜</h3>
<svg id="s2" width="600" height="400">
  <!--定义特效对象-->
  <defs>
    <!--linearGraident-->
    <!--filter-->
    <filter id="f3">
      <feGaussianBlur stdDeviation="3"></feGaussianBlur>
    </filter>
    <filter id="f6">
      <feGaussianBlur stdDeviation="6"></feGaussianBlur>
    </filter>
  </defs>
  <text x="50" y="100" font-size="70">高斯模糊滤镜</text>
  <text x="50" y="200" font-size="70" filter="url(#f3)">高斯模糊滤镜</text>
  <text x="50" y="300" font-size="70" filter="url(#f6)">高斯模糊滤镜</text>
</svg>
<script>
</script>
</body>
</html>

svg2-12

WangShuXian6 commented 5 years ago

第三方绘图工具库——Two.js的使用

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    svg,
    canvas {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>第三方绘图工具库——Two.js的使用</h3>
<div id="container"></div>
<script src="../lib/two.js"></script>
<script>
  var params = {width: 800, height: 400, type: Two.Types.svg};
  //var params = {width:800, height:400, type: Two.Types.webgl};
  //var params = {width:800, height:400, type: Two.Types.canvas};
  var two = new Two(params).appendTo(container);
  //添加一个圆形
  var circle = two.makeCircle(200, 200, 100);
  circle.fill = '#fa3';
  circle.opacity = 0.6;
  circle.stroke = '#a80';
  circle.linewidth = 8;
  //添加一个矩形——定位点在矩形中央
  var rect = two.makeRectangle(600, 200, 200, 200);
  rect.fill = '#2bf';
  rect.stroke = 'transparent';
  //记得更新界面视图,把内存中的图形绘制到浏览器
  two.update();
</script>
</body>
</html>

svg2-13-1


<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    svg,
    canvas {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>第三方绘图工具库——Two.js的使用</h3>
<div id="container"></div>
<script src="../lib/two.js"></script>
<script>
  var params = {width: 800, height: 400, type: Two.Types.svg};
  //var params = {width:800, height:400, type: Two.Types.webgl};
  //var params = {width:800, height:400, type: Two.Types.canvas};
  var two = new Two(params).appendTo(container);
  //添加一个圆形
  var circle = two.makeCircle(200, 200, 100);
  circle.fill = '#fa3';
  circle.opacity = 0.6;
  circle.stroke = '#a80';
  circle.linewidth = 8;
  //添加一个矩形——定位点在矩形中央
  var rect = two.makeRectangle(600, 200, 200, 200);
  rect.fill = '#2bf';
  rect.stroke = 'transparent';
  /*********
   *矩形旋转 —— (1)不具备累加效果 (2)旋转的轴点都是当前元素的定位点
   *********/
  /*rect.rotation = 5*Math.PI/180;
  rect.rotation = 5*Math.PI/180;
  rect.rotation = 2*Math.PI/180;*/
  /*rect.rotation = 45*Math.PI/180;*/
  //使用定时器动画
  var deg = 0;
  two.on('update', function () { //每次调用two.update()就会触发该事件
    deg += 3;
    rect.rotation = deg * Math.PI / 180;
  })
  two.play(); //每秒钟调用60次two.update()
</script>
</body>
</html>

Kapture 2019-03-19 at 14 49 15


<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    svg,
    canvas {
      background: #f0f0f0;
    }
  </style>
</head>
<body>
<h3>第三方绘图工具库——Two.js的使用</h3>
<div id="container"></div>
<script src="../lib/two.js"></script>
<script>
  var params = {width: 800, height: 400, type: Two.Types.svg};
  //var params = {width:800, height:400, type: Two.Types.webgl};
  //var params = {width:800, height:400, type: Two.Types.canvas};
  var two = new Two(params).appendTo(container);
  //添加一个圆形
  //var circle = two.makeCircle(200,200,100);
  var circle = two.makeCircle(-200, 0, 100);
  circle.fill = '#fa3';
  circle.opacity = 0.6;
  circle.stroke = '#a80';
  circle.linewidth = 8;
  //添加一个矩形——定位点在矩形中央
  //var rect = two.makeRectangle(600,200,200,200);
  var rect = two.makeRectangle(200, 0, 200, 200);
  rect.fill = '#2bf';
  rect.stroke = 'transparent';
  /***
   * 使用“分组”将多个图形组合为一个大的图形
   */
  var g = two.makeGroup(circle, rect);
  //小组默认的定位点/旋转轴点在画布的(0,0)
  g.translation.x = 400; //平移小组的定位点
  g.translation.y = 200; //平移小组的定位点
  //小组内的图形的定位点都是相对于小组的轴点的
  //使用定时器动画
  var deg = 0;
  two.on('update', function () { //每次调用two.update()就会触发该事件
    deg += 3;
//rect.rotation = deg*Math.PI/180;
    g.rotation = deg * Math.PI / 180;
  })
  two.play(); //每秒钟调用60次two.update()
</script>
</body>
</html>

Kapture 2019-03-19 at 14 51 09


WangShuXian6 commented 5 years ago

SVG 线条动画

IVWEB 线条动画 https://codepen.io/WangShuXian6/pen/KEBQYw

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    .text {
      fill: none;
      stroke-width: 5;
      stroke-dasharray: 0 300;
      stroke-dashoffset: 0;
    }

    .text:nth-child(3n + 1) {
      stroke: #fa637f;
      animation: stroke 6s ease-in-out forwards;

    }

    .text:nth-child(3n + 2) {
      stroke: #92d0fa;
      animation: stroke1 6s ease-in-out forwards;

    }

    .text:nth-child(3n + 3) {
      stroke: #fbbe37;
      animation: stroke2 6s ease-in-out forwards;

    }

    @keyframes stroke {
      100% {
        stroke-dashoffset: 1000;
        stroke-dasharray: 80 160;
      }
    }

    @keyframes stroke1 {
      100% {
        stroke-dashoffset: 1080;
        stroke-dasharray: 80 160;
      }
    }

    @keyframes stroke2 {
      100% {
        stroke-dashoffset: 1160;
        stroke-dasharray: 80 160;
      }
    }

    /* Other styles */
    html, body {
      height: 100%;
    }

    body {
      background: #212121;
      background-size: .2em 100%;
      font: 14.5em/1 Open Sans, Impact;
      text-transform: uppercase;
      margin: 0;
    }

    svg {
      position: absolute;
      width: 100%;
      height: 100%;
    }
  </style>
  <title>Title</title>
</head>
<body>

<svg viewBox="0 0 1320 300">

  <!-- Symbol -->
  <symbol id="s-text">
    <text text-anchor="middle"
          x="50%" y="50%" dy=".35em">
      MIDOCI
    </text>
  </symbol>

  <!-- Duplicate symbols -->
  <use xlink:href="#s-text" class="text"
  ></use>
  <use xlink:href="#s-text" class="text"
  ></use>
  <use xlink:href="#s-text" class="text"
  ></use>

</svg>

</body>
</html>

Kapture 2019-03-19 at 15 40 38



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SVG</title>
<style type="text/css">
svg {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: #fff;
}

path {
  fill: transparent;
  stroke: #92d0fa;
  stroke-dasharray: 255%;
  animation: outline 5s infinite alternate;
}

@keyframes outline {
  0% {
    stroke-dashoffset: 255%;
  }
  100% {
    stroke-dashoffset: 0;
  }
}

WangShuXian6 commented 2 months ago

mo.js

https://github.com/mojs https://mojs.github.io/ 用于 Web 的动态图形工具

Mo · JS 是一个 JavaScript 动态图形库,它是一个快速、支持 Retina、模块化和开源的库。与其他库相比,它具有不同的语法和代码动画结构方法。声明式 API 为您提供了对动画的完全控制,使其易于自定义。

npm

npm install @mojs/core
import mojs from '@mojs/core';

new mojs.Html({
  // ...
});

与 React 一起使用

npm i react react-dom @mojs/core

示例1

图片

src\mojs\circle.tsx

import React, { useRef, useEffect, useState, useCallback } from "react";
import mojs from "@mojs/core";
import styles from './index.module.css'

/**
 * Usage:
 * import { FCircle } from "./mojs/circle";
 *
 * <FCircle duration={1000}/>
 */

interface FCircleProps {
  duration: number;
}

export const FCircle = ({ duration }:FCircleProps) => {
  const animDom = useRef<HTMLDivElement>(null);
  const bouncyCircle = useRef<mojs.Shape>(null);
  // 添加一些方法来监听动画事件,并使用 Reacts useState 将其保存为本地状态:
  const [isOpen, setIsOpen] = useState<boolean>(false);
  const [isAnimating, setIsAnimating] = useState<boolean>(false);

  useEffect(() => {
    // Prevent multiple instansiations on hot reloads
    // 防止热重载时出现多个实例
    // 通过检查是否已经分配了 ref,我们可以防止动画在重新渲染时再次实例化(在使用热重载时非常有用):
    if (bouncyCircle.current) return;

    // Assign a Shape animation to a ref
    // 首先,我们创建一个钩子,并利用其不可变对象,并将我们的 MoJS 动画分配给它。这样我们以后就可以使用它来控制我们的动画
    bouncyCircle.current = new mojs.Shape({
      // 为了获取我们想要附加动画的 DOM 元素的引用,我们可以使用一个钩子,并将其附加到容器上:useRef
      parent: animDom.current,
      shape: "circle",
      fill: { "#FC46AD": "#F64040" },
      radius: { 50: 200 },
      duration: duration,
      isShowStart: true,
      easing: "elastic.inout",
      onStart() {
        setIsAnimating(true);
      },
      onComplete() {
        setIsAnimating(false);
      },
    });
    //如果我们想直接播放动画,我们可以直接在 bouncyCircle 声明之后添加。bouncyCircle.current.play();
  });

  // Update the animation values when the prop changes
  useEffect(() => {
    if (!bouncyCircle.current) return;
    bouncyCircle.current.tune({ duration: duration });
    isOpen
      ? bouncyCircle.current.replayBackward()
      : bouncyCircle.current.replay();
    setIsOpen(!isOpen);
  }, [duration]);

  const clickHandler = useCallback(() => {
    // If the "modal" is open, play the animation backwards, else play it forwards
    // 现在,让我们添加一个按钮,点击后播放动画。为了控制动画,我们现在可以使用 bouncyCircle.current.play() 引用 MoJS 动画;
    isOpen ? bouncyCircle.current.playBackward() : bouncyCircle.current.play();
    setIsOpen(!isOpen);
  }, [isOpen]);

  return (
    <div className="MojsExample">
      <div className={styles.content}>
        <h1>MoJS React Example</h1>
        <p>Using hooks</p>
        <button className="button" onClick={clickHandler}>
          {isAnimating && isOpen ? "Animating" : isOpen ? "Close" : "Open"}
        </button>
      </div>
      <div ref={animDom} className='f-circle-ani'></div>
    </div>
  );
};

src\mojs\index.module.css

.content {
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
}

.f-circle-ani {
}

src\App.tsx

import "./App.css";
import { FCircle } from "./mojs/circle";
function App() {
  return (
    <>
      <FCircle duration={2000} />
    </>
  );
}

export default App;

package.json

{
  "name": "svg",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "@mojs/core": "^1.7.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "@typescript-eslint/eslint-plugin": "^7.15.0",
    "@typescript-eslint/parser": "^7.15.0",
    "@vitejs/plugin-react-swc": "^3.5.0",
    "eslint": "^8.57.0",
    "eslint-plugin-react-hooks": "^4.6.2",
    "eslint-plugin-react-refresh": "^0.4.7",
    "typescript": "^5.2.2",
    "vite": "^5.3.4"
  }
}
WangShuXian6 commented 2 months ago

SVG 路径动画

示例1

https://codepen.io/WangShuXian6/pen/YzoNMXv 图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG Scroll Effect</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="background">
        <img src="background.jpg" alt="Background Image">
    </div>
    <svg class="curve" width="100%" height="200">
        <path id="curvePath" d="M10 80 Q 95 10 180 80 T 330 80" fill="none" stroke="red" stroke-width="5"/>
    </svg>
    <script src="script.js"></script>
</body>
</html>
/* styles.css */
body, html {
    margin: 0;
    padding: 0;
    height: 2000px; /* 增加页面高度以实现滚动效果 */
}

.background {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    overflow: hidden;
}

.background img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.curve {
    position: fixed;
    top: 50px; /* 根据需要调整位置 */
    left: 0;
    z-index: 1;
}
// script.js
window.addEventListener('scroll', () => {
    const curve = document.querySelector('#curvePath');
    const pathLength = curve.getTotalLength();

    // Ensure the path is not visible initially
    curve.style.strokeDasharray = pathLength;
    curve.style.strokeDashoffset = pathLength;

    const scrollPosition = window.scrollY;
    const maxScroll = document.body.scrollHeight - window.innerHeight;
    const drawLength = (scrollPosition / maxScroll) * pathLength;

    curve.style.strokeDashoffset = pathLength - drawLength;
});

// Set the initial dash array and dash offset to hide the path
document.addEventListener('DOMContentLoaded', () => {
    const curve = document.querySelector('#curvePath');
    const pathLength = curve.getTotalLength();
    curve.style.strokeDasharray = pathLength;
    curve.style.strokeDashoffset = pathLength;
});

React 版本

src\components\SVGScrollEffect.tsx

import React, { useEffect, useRef } from 'react';
import './SVGScrollEffect.css';
import BG from './BingWallpaper.jpg'

const SVGScrollEffect: React.FC = () => {
  const pathRef = useRef<SVGPathElement>(null);

  useEffect(() => {
    const handleScroll = () => {
      if (pathRef.current) {
        const pathLength = pathRef.current.getTotalLength();

        // Ensure the path is not visible initially
        pathRef.current.style.strokeDasharray = `${pathLength}`;
        pathRef.current.style.strokeDashoffset = `${pathLength}`;

        const scrollPosition = window.scrollY;
        const maxScroll = document.body.scrollHeight - window.innerHeight;
        const drawLength = (scrollPosition / maxScroll) * pathLength;

        pathRef.current.style.strokeDashoffset = `${pathLength - drawLength}`;
      }
    };

    // Set initial dash array and dash offset to hide the path
    if (pathRef.current) {
      const pathLength = pathRef.current.getTotalLength();
      pathRef.current.style.strokeDasharray = `${pathLength}`;
      pathRef.current.style.strokeDashoffset = `${pathLength}`;
    }

    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

  return (
    <div className="background">
      <img src={BG} alt="Background" />
      <svg className="curve" width="100%" height="200">
        <path
          ref={pathRef}
          d="M10 80 Q 95 10 180 80 T 330 80"
          fill="none"
          stroke="red"
          strokeWidth="5"
        />
      </svg>
    </div>
  );
};

export default SVGScrollEffect;

src\components\SVGScrollEffect.css

body, html {
    margin: 0;
    padding: 0;
    height: 2000px; /* 增加页面高度以实现滚动效果 */
  }

  .background {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    overflow: hidden;
  }

  .background img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .curve {
    position: fixed;
    top: 50px; /* 根据需要调整位置 */
    left: 0;
    z-index: 1;
  }

src\App.tsx

import "./App.css";
import SVGScrollEffect from "./components/SVGScrollEffect";

function App() {
  return (
    <>
      <SVGScrollEffect />
    </>
  );
}

export default App;