likes
comments
collection
share

SVG 绘图

作者站长头像
站长
· 阅读数 14

1. SVG 简介及 SVG 与 canvas 对比

1.1. SVG VS Canvas
canvas 绘图SVG 绘图
类型位图矢量图
缩放失真不会失真
内容JS 绘制元素 / 标签绘制
事件绑定只能为整个画布绑定, 非常不方便很容易为某个图形 / 图像绑定监听
颜色细节丰富不够丰富
应用领域统计图, 照片, 网页游戏统计图, 图标, 地图应用
1.2. SVG 简介

Scalable vector Graph, 可缩放的矢量图

  • SVG 技术最早在 2000 年就有了, 作为一种 XML 的扩展应用存在 后来 H5 标准把 SVG 标签纳入到 H5 中, 进行了一部分精简
1.2.1. H5 标准之前使用 SVG 的方法
  • 编写一个 XML 文档, Ex: my.svg, 书写 SVG 标签
  • 再编写一个 HTML 文档, 其中包含 <img src="my.svg" />
1.2.2. H5 标准之后使用 SVG 的方法
  • H5 标准把 SVG 标签采纳进来, 可以直接在 H5 文件中书写

  • <svg> 标签默认是一个 300 * 150 的 inline-block

    • 注意:

      1. SVG 画布的尺寸可以使用 CSS 样式, HTML 属性, JS 对象属性指定!
      2. SVG 画布中不允许放置普通的 HTML 标签
      3. SVG 相关的标签也不允许放在 SVG 画布外
1.2.3. SVG, 图形 / 图像标签的共性
  1. 默认没有尺寸, 尺寸相关属性是必需
  2. 初始化都只有填充色, 没有描边
  3. SVG 标签的样式可以用 HTML 标签属性形式声明, 也可以类似于 CSS 形式声明 但 SVG 样式属性和 CSS 样式属性互不通用
  4. 可以使用核心 DOM 操作访问 SVG 元素的属性( getAttribute / setAttribute ) 不能使用 HTML DOM 方式来操作
  5. 动态创建 SVG 图形标签可以使用拼接 HTML 字符串方式, 也可以使用 document.createElementNS( '名称空间', '元素名' )

2. 使用 SVG 的绘图

2.1. 绘制矩形
<svg width="500" height="400">
	<rect width="100" height="80" x="0" y="320" fill="#F00" fill-opacity="0.3" stroke="#A00" stroke-width="5" stroke-opacity='0.8'></rect>
</svg>
  • Ex: SVG 画布正中央绘制一个矩形, 填充 青色半透明, 描边红色半透明 当鼠标移入该矩形, 半透明变为不透明
    <svg width="500" height="400">
    	<rect id="svgTest" width="200" height="100" x="150" y="150" fill="#0FF" fill-opacity="0.5" stroke="#F00" stroke-opacity="0.5"></rect>
    </svg>
    <script type="text/javascript">
    	let svgTest = document.getElementById('svgTest')
    	svgTest.addEventListener('mouseenter', function () {
    		this.setAttribute('fill-opacity', 1)
        	this.setAttribute('stroke-opacity', 1)
    	})
    	svgTest.addEventListener('mouseleave', function () {
    		this.setAttribute('fill-opacity', 0.5)
        	this.setAttribute('stroke-opacity', 0.5)
    	})
    </script>
    
2.2. 绘制圆形
<svg width="500" height="400">
	<circle r="50" cx="250" cy="200"></circle>
</svg>
  • Ex: 使用 SVG 在画布上随机绘制 30 个圆形, 大小随机, 位置随机, 颜色填充随机 点击某个圆形时, 它渐渐变大, 变淡....直至消失, 从 DOM 树上删除
    <svg width="500" height="500" id="svgTest"></svg>
    <script type="text/javascript">
    	let svgTest = document.getElementById('svgTest')
    	for (let i = 0; i < 30; i++) {
    		let circleItem = document.createElementNS('http://www.w3.org/2000/svg', 'circle')
    		circleItem.setAttribute('r', randomNumFn(20, 100)) // 半径
        	circleItem.setAttribute('cx', randomNumFn(0, 500)) // 圆心 x
        	circleItem.setAttribute('cy', randomNumFn(0, 500)) // 圆心 y
        	circleItem.setAttribute('fill', randomColorFn(0, 255)) // 填充色
        	circleItem.setAttribute('fill-opacity', 1)
    		// 为 svg 添加原型
    		svgTest.appendChild(circleItem)
    		// 为每个圆绑定事件
    		circleItem.addEventListener('click', function () {
    			let that = this
    			let timer = null
    			clearInterval(timer)
    			timer = setInterval(function () {
    				// 修改圆形半径 每次变大 5%
    				let changeR = that.getAttribute('r')
    				changeR *= 1.05
    				that.setAttribute('r', changeR)
    				// 修改圆形的透明度 每次减少 5%
    				let changeOpacity = that.getAttribute('fill-opacity')
    				changeOpacity *= 0.95
    				that.setAttribute('fill-opacity', changeOpacity)
    				// 当透明度几乎不可见时 就从 DOM 树上移除
    				if (0.001 >= changeOpacity) {
    					clearInterval(timer)
    					svgTest.removeChild(that)
    				}
    			}, 30)
    		})
    	}
    	// random Number, 返回指定范围内的随机整数
    	function randomNumFn(min, max) {
    		return Math.floor(Math.random() * (max - min) + min)
    	}
    	// random color, 返回指定范围内的随机颜色
    	function randomColorFn(min, max) {
    		let r = randomNumFn(min, max)
    		let g = randomNumFn(min, max)
    		let b = randomNumFn(min, max)
    		return `rgb(${r}, ${g}, ${b})`
    	}
    </script>
    
2.3. 绘制椭圆
<svg width="500" height="400">
	<ellipse rx="100" ry="50" cx="250" cy="200" fill="#0FF" fill-opacity="0.5" stroke="#F00" stroke-opacity=""></ellipse>
</svg>
2.4. 绘制直线
<svg width="500" height="400">
	<line x1="50" y1="50" x2="450" y2="350" stroke="#00F" stroke-width="50" stroke-linecap=""></line>
</svg>
  • Ex: 绘制图表 SVG 绘图
<svg width="500" height="500">
	<g stroke="#F00" stroke-width="50" stroke-linecap="round">
		<line x1="50" y1="50" x2="50" y2="50" stroke="#0ff"></line>
    	<line x1="150" y1="50" x2="350" y2="50"></line>    
    	<line x1="50" y1="150" x2="50" y2="150"></line>
    	<line x1="150" y1="150" x2="350" y2="150"></line>    
    	<line x1="50" y1="250" x2="50" y2="250"></line>
    	<line x1="150" y1="250" x2="350" y2="250"></line>
	</g>
</svg>
  • 扩展: 可以使用 <g></g> 标签创建一个 group, 它本身不可见, 但可以盛放其他子标签, 子标签会自动继承所在小组的属性值
2.5. 绘制折线
<svg width="500" height="500">
	<polyline points="x1, y1 x2,y2 x3,y3 ......" fill="transparent" stroke="#000"></polyline>
</svg>
  • Ex: 使用折线绘制五角星
    <svg width="500" height="500">
    	<polyline points="50,160 350,160 100,320 200,50 300,320 50,160" stroke="#f00" fill="transparent"></polyline>
    </svg>
    
2.6. 绘制多边形
<svg width="500" height="500">
	<polygon points="x1,y1 x2,y2 x3,y3 ......"></polygon>
</svg>
  • Ex: 绘制 SVG 绘图
<svg width="500" height="500">
	<g fill="#000">
		<polygon points="0,0 600,0 300,200"></polygon>
    	<polygon points="0,60, 300,260 600,60 600,400 0,400 0,60"></polygon>
	</g>
</svg>
2.7. 绘制文本

提示: SVG 画布上不能使用普通的 HTML 标签, 如 <span></span>

<svg>
	<text alignment-baseline="before-edge" font-size="50" font-family="SimHei" x="100" y="200">文本内容</text>
</svg>
2.8. 绘制图像
<svg width="500" height="500">
	<image xline="img/p4.png" width="200" height="100" x="0" y="0"></image>
</svg>

3. 在 SVG 中实现渐变

  1. 首先在 <defs></defs> 中声明所需要的渐变对象

    <svg width="500" height="500">
    	<!-- define Effects 定义特效对象 -->
      <defs>
      	<!-- 渐变对象的定位点相对于目标对象 而不是画布 -->
        <linearGradient id="gradientOne" x1="0" y1="0" x2="100%" y2="0">
        	<stop offset="0" stop-color="#f00"></stop>
          <stop offset="0.5" stop-color="#ff0"></stop>
          <stop offset="1" stop-color="#00f"></stop>
        </linearGradient>
        <linearGradient id="gradientTwo">
        	<stop offset="0" stop-color="#f00"></stop>
          <stop offset="1" stop-color="#f00" stop-opacity="0"></stop>
        </linearGradient>
      </defs>  
    </svg>
    
  2. 然后创建可见图形对象, 声明 fill / stroke 使用渐变对象

    <svg width="500" height="500">
    	<!-- 定义容器 应用渐变对象 -->
      <rect width="400" height="100" fill="url(#gradientTwo)"></rect>
      <rect width="400" height="100" stroke="url(#gradientOne)" x="200" y="300" fill="transparent"></rect>
    </svg>
    

4. 使用 SVG 滤镜特效对象

4.1. 使用步骤
  1. 首先在 <defs></defs> 元素中声明所需要的滤镜对象

    <svg width="500" height="500">
    	<!-- define Effects 定义特效对象 -->
      <defs>
      	<filter id="filterTestOne">
        	<!-- filter effects -->
          <feGaussianBlur stdDeviation="3"></feGaussianBlur>
        </filter>
        <filter id="filterTestTwo">
        	<!-- filter effects -->
          <feGaussianBlur stdDeviation="6"></feGaussianBlur>
        </filter>
      </defs>
    </svg>
    
  2. 创建可见图形对象, 声明 filter 使用滤镜对象

    <svg width="500" height="500">
    	<g font-size="66">
      	<text x="0" y="0" alignment-baseline="before-edge">lcy</text>
        <text x="0" y="100" alignment-baseline="before-edge" filter="url(#filterTestOne)">lcy</text>
        <text x="0" y="200" alignment-baseline="before-edge" filter="url(#filterTestTwo)">lcy</text>
      </g>
    </svg>