前言
上一篇文章中主要介绍了 SVG 的一些容器元素以及一些实际的。以及一些实际的应用场景。这一篇文章,将会介绍 SVG 内的渐变以及 clipPath 剪切的操作。
往期文章
SVG 渐变
线性渐变沿着直线改变颜色,要插入一个线性渐变,你需要在SVG文件的defs元素内部,创建一个<linearGradient> 节点。
linearGradient 线性渐变
渐变 linearGradient 需要再 <defs> 内进行声明。通过 <stop> 来分割渐变的区域
可用在 fill 或 stroke 中使用渐变
属性:
- x1 开始点的 x 坐标
- y1 开始点的 y 坐标
- x2 结束点的 x 坐标
- y2 结束点的 y 坐标
- spreadMethod 到达终点后的渐变行为
- pad 中止 (默认)
- reflect 重复来回(0% -> 100% -> 0%)
- repeat 重复(0% -> 100% jumpTo 0% -> 100%)
- gradientUnits 渐变容器应用不同的坐标系
- objectBoundingBox(默认) 以被渐变元素作为坐标系
- userSpaceOnUse 以 SVG 画布作为坐标系
- gradientTransform 渐变变形(后面单独说明)
通过 x1,y1 和 x2,y2 来确定渐变的方向和渐变范围
设置 gradientUnits:userSpaceOnUse。位置坐标设置 0 - 1就不是百分比了,而是当前所在 SVG 容器的坐标值
简单使用
例1:在 fill 和 stroke 中使用
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<linearGradient id="Gradient1" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue" stop-opacity="0.2"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="100" height="100" fill="url(#Gradient1)"></rect>
</svg>
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<linearGradient id="Gradient1" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#FF0000"/>
<stop offset="100%" stop-color="#0000FF" stop-opacity="0.2"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="100" height="100" stroke="url(#Gradient1)" stroke-width="10" fill="none"></rect>
</svg>
stop-color 可以使用 rgba 格式
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<linearGradient id="Gradient2" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="rgba(255,0,0,.6)"/>
<stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="100" height="100" fill="url(#Gradient2)"></rect>
</svg>
应用不同的坐标系 userSpaceOnUse & objectBoundingBox
<svg class="border" width="250" height="250" viewBox="0 0 250 250">
<defs>
<linearGradient id="Gradient_objectBoundingBox" x1="0" y1="0" x2="0" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue" stop-opacity="0.2"/>
</linearGradient>
</defs>
<defs>
<linearGradient id="Gradient_userSpaceOnUse" x1="130" y1="10" x2="130" y2="110" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue" stop-opacity="0.2"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="100" height="100" fill="url(#Gradient_objectBoundingBox)"></rect>
<rect x="130" y="10" width="100" height="100" fill="url(#Gradient_userSpaceOnUse)"></rect>
</svg>
spreadMethod 到达终点后的渐变行为
在 objectBoundingBox 坐标系下更为明显。下面的示例将使用 userSpaceOnUse 坐标系
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- 重复来回 -->
<linearGradient id="Gradient3" x1="0" y1="0" x2="0" y2="80" spreadMethod="reflect" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="rgba(255,0,0,1)"/>
<stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient3)"></rect>
<rect x="100" y="10" width="80" height="180" fill="url(#Gradient3)"></rect>
</svg>
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- 重复 -->
<linearGradient id="Gradient4" x1="0" y1="0" x2="0" y2="80" spreadMethod="repeat" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="rgba(255,0,0,1)"/>
<stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient4)"></rect>
<rect x="100" y="10" width="80" height="180" fill="url(#Gradient4)"></rect>
</svg>
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- 中止,以最终目标颜色继续填充 -->
<linearGradient id="Gradient5" x1="0" y1="0" x2="0" y2="80" spreadMethod="pad" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="rgba(255,0,0,1)"/>
<stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient5)"></rect>
<rect x="100" y="10" width="80" height="180" fill="url(#Gradient5)"></rect>
</svg>
radialGradient 径向渐变
径向渐变与线性渐变相似,只是它是从一个点开始发散绘制渐变。创建径向渐变需要在文档的defs中添加一个<radialGradient>元素
可用在 fill 或 stroke 中使用渐变
属性:
- cx 中心点 x 坐标
- cy 中心点 y 坐标
- r 圆的半径
- fx 焦点的 x 坐标
- fy 焦点的 y 坐标
- fr 焦点的 半径。焦点的颜色继承渐变最初的颜色
- spreadMethod 到达终点后的渐变行为
- pad 中止 (默认)
- reflect 重复来回(0% -> 100% -> 0%)
- repeat 重复(0% -> 100% jumpTo 0% -> 100%)
- gradientUnits 渐变容器应用不同的坐标系
- objectBoundingBox(默认) 以被渐变元素作为坐标系
- userSpaceOnUse 以 SVG 画布作为坐标系
- gradientTransform 渐变变形(后面单独说明)
简单使用
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="Gradient1" cx="0.5" cy="0.5" r="0.5">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" width="100" height="100" fill="url(#Gradient1)"></rect>
</svg>
定义焦点
在默认情况下焦点为园的中点。
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- 不设置焦点默认焦点位置在中心点 -->
<radialGradient id="Gradient2" cx="0.5" cy="0.5" r="0.5" >
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="Gradient3" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25" >
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient2)"></rect>
<rect x="10" y="100" width="80" height="80" fill="url(#Gradient3)"></rect>
</svg>
不同的坐标系及 spreadMethod
与 linearGradient 相同。效果如下
userSpaceOnUse
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="Gradient7" cx="100" cy="100" r="80" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient7)"></rect>
</svg>
spreadMethod
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="Gradient4" cx="0.5" cy="0.5" r="0.2" spreadMethod="pad">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient4)"></rect>
</svg>
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="Gradient5" cx="0.5" cy="0.5" r="0.2" spreadMethod="repeat">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient5)"></rect>
</svg>
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="Gradient6" cx="0.5" cy="0.5" r="0.2" spreadMethod="reflect">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#Gradient6)"></rect>
</svg>
clipPath 剪切
定义一条剪切路径,可作为其他元素的 clip-path 属性的值。 剪切路径限制了图形的可见范围。从概念上来说,如果图形超出了当前剪切路径所包围的区域,那么超出部分将不会绘制。
clipPath 定义的路径,在定义路径里的会被展示,外侧的则被剪切
属性:
- clipPathUnits 裁剪容器应用不同的坐标系(同patternContentUnits)
- objectBoundingBox(默认) 以被裁剪元素作为坐标系
- userSpaceOnUse 以 SVG 画布作为坐标系
简单使用
在一个矩形中裁剪出一个圆
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<clipPath id="cut">
<!-- 裁剪元素的颜色不会对裁剪有效果 -->
<circle cx="100" cy="100" r="50" fill="red">
</clipPath>
</defs>
<rect x="0" y="0" width="200" height="200" fill="green" clip-path="url(#cut)"/>
</svg>
通过 clipPath 实现填充动画
两个图形:爱心图形的描边和被爱心图形裁剪背景色矩形
实现原理:设置固定位置的裁剪图形,通过动态改变背景矩形的位置来实现填充的效果
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
<defs>
<clipPath id="cut3">
<path id="heart" transform="scale(0.2)" d="M667.786667 117.333333C832.864 117.333333 938.666667 249.706667 938.666667 427.861333c0 138.250667-125.098667 290.506667-371.573334 461.589334a96.768 96.768 0 0 1-110.186666 0C210.432 718.368 85.333333 566.112 85.333333 427.861333 85.333333 249.706667 191.136 117.333333 356.213333 117.333333c59.616 0 100.053333 20.832 155.786667 68.096C567.744 138.176 608.170667 117.333333 667.786667 117.333333z"></path>
</clipPath>
</defs>
<rect id="rect" x="0" y="180" width="200" height="160" fill="#E91E63" clip-path="url(#cut3)"/>
<use href="#heart" fill="transparent" stroke="#E91E63" stroke-width="20"></use>
</svg>
<div class="input">
<div>输入 0 - 100</div>
<input type="text" onchange="setLikeValue(event)">
</div>
function setLikeValue(e){
const value = e.target.value;
const reg = /^[0-9]+$/;
if(!reg.test(value) || +value > 100) return
// 初始 y - 高度所占高
anime({
targets: '#rect',
y:180 - (+value/100) * 160
});
}
效果和mask制作的填充基本一致。mask实现填充
比较 clipPath 与 mask
- clipPath 是对定义区域将路径内的内容进行裁剪
- mask 是对定义内的内容通过自身透度合成新的内容
- clipPath 不能通过 fill stroke opacity 控制展示内容,只进行路径裁剪。mask 是合成,可以通过 fill stroke opacity 控制展示内容
- clipPath 能实现的 mask 都能实现。且还可以控制最后展示的内容。在一定程度上 mask 是更高级版的 clipPath
最后
至此,SVG 的基础篇已经结束,下面我会继续为大家带来 SVG 滤镜及动画使用方法的详细介绍。喜欢的朋友可以关注一下。
参考资料