SVG路径<Path>标签详解,一次搞懂所有命令参数
Posted gxyzlxf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SVG路径<Path>标签详解,一次搞懂所有命令参数相关的知识,希望对你有一定的参考价值。
在上一篇文章 什么是SVG?——SVG快速入门 中我对SVG做了基础的介绍,这篇文章将集中讲解<path>标签
本站链接:什么是SVG?——SVG快速入门_gxyzlxf的博客-CSDN博客
稀土掘金链接:什么是SVG?——SVG快速入门 - 掘金
path的所有命令如下,除了M、L和Z 非常简单外,我会在这篇文章中对剩下的命令的用法进行详细介绍。
M = moveto 起始
L = lineto 连线
H = horizontal lineto 水平线
V = vertical lineto 垂直线
C = curveto 三次贝塞尔曲线
S = smooth curveto 三次贝塞尔曲线
Q = quadratic Bézier curve 二次贝塞尔曲线
T = smooth quadratic Bézier curveto 二次贝塞尔曲线
A = elliptical Arc 椭圆弧
Z = closepath 闭合(从最后一个点连直线到起始点)
使用大写字母表示绝对位置,小写字母表示相对位置(相对于起点的位置,向右向下为正)。
一、H和V命令,画水平/垂直线
这两个命令非常简单,命令后面跟上一个参数即可。
以H为例进行说明:使用大写H是绝对位置,表示从前一个点向该X坐标画一条水平线,比如下面第一行代码,相当于从(50,50)向(150,50)连线,线的长度为100。
而使用小写h是相对位置,相当于指定线的长度,长度为正表示向右向下,比如下面第二行代码,表示从(50,50)画一条长为150的水平线。
V和H用法完全相同,只不过把水平变成垂直而已。下面三行代码的效果如下:
<path d="M 50 50 H 150" stroke="blue" stroke-width="5" fill="none" />
<path d="M 50 80 h 150" stroke="blue" stroke-width="5" fill="none" />
<path d="M 50 80 v 50" stroke="blue" stroke-width="5" fill="none" />
二、Q和T命令,画二次贝塞尔曲线
(一)Q命令
Q后面跟两组坐标 x1 y1 x y 分别是控制点和终点,控制点的作用是确定起点和终点的曲线斜率
例子如下:前两行代码一个用的是大写Q,一个是小写q,绘制出了相同的形状。
<path d="M 50 250 Q 100 150 150 250" stroke="blue" stroke-width="5" fill="none" />
<path d="M 200 250 q 50 -100 100 0" stroke="blue" stroke-width="5" fill="none" />
<path d="M 350 250 q 20 -100 100 0" stroke="blue" stroke-width="5" fill="none" />
(二)T命令
T命令也是用来画二次贝塞尔曲线,但是后面只跟一组坐标,就是终点的坐标。
它其实是一种简写,让程序根据前一个控制点推测出这次的控制点(关于终点中心对称),所以使用T之前必须有一个控制点,换句话说,T必须跟着Q或T使用。如果单独使用,会默认控制点就是终点,则画出的是直线而不是曲线。
它的原理示意图是:
例子:第2行代码就是单独使用T命令的例子,画出的是直线
<path d="M 50 450 q 50 -100 100 0 t 100 0 t 50 0" stroke="blue" stroke-width="5" fill="none" />
<path d="M 450 350 t 50 80" stroke="blue" stroke-width="5" fill="none" />
三、C和S命令,画三次贝塞尔曲线
(一)C命令
画三次贝塞尔曲线需要三组坐标点x1 y1 x2 y2 x y,分别是起点的控制点,用来控制曲线射出的方向;终点的控制点,用来控制曲线射入的方向;最后是终点。
原理示意图:
例:
<path d="M 100 550 C 50 600 250 600 200 550" stroke="blue" stroke-width="5" fill="none" />
(二)S命令
S命令和T命令一样,属于一种简写方式。只定义第二个控制点和终点,让程序根据之前的命令推测第一个控制点的位置(与前一条命令的第二个控制点关于前一条命令的终点中心对称),同样必须跟着C或S使用。如果单独使用,会默认两个控制点在同一位置,就变成了二次贝塞尔曲线。听着有点绕,看下面的原理示意图就很清晰了:
例:第2行代码就是单独使用T命令的例子,画出的是二次贝塞尔曲线
<path d="M 300 550 C 250 600 450 600 400 550 s 150 -50 100 0" stroke="blue" stroke-width="5" fill="none" />
<path d="M 700 550 S 650 500 600 550" stroke="blue" stroke-width="5" fill="none" />
四、A命令,画椭圆弧
个人觉得是最复杂的一个命令,试了半天没试明白,又百度了半天,然后再自己尝试,总算搞懂了。
A后面跟的参数有点多,分别是:
1.x轴半径(可以写比例,写比例时默认用符合条件的最小值,参数4就没有意义了)
2.y轴半径(可以写比例,写比例时默认用符合条件的最小值,参数4就没有意义了)
3.x轴旋转度数(顺时针方向为正)
在前面三个参数确定的情况下,满足当前点到指定点(X,Y)位置条件的圆弧总是有四条,如图:
4.优弧还是劣弧(0或1,0表示劣弧,1表示优弧) 排除一半。(忘了椭圆是不是和圆一样有优弧和劣弧的概念,反正就是长度短的一条路径和长度长的一条路径)
5.弧线方向(0或1,0表示从起点到终点沿逆时针画弧,1表示从起点到终点沿顺时针画弧)再排除一半,只剩唯一一条。
6.终点x
7.终点y
一口气看这么多参数确实不好记,参照下面的例子可以帮助你更好的理解。
例:
1.x轴半径和y轴半径的比是1:2,不旋转,从起点逆时针画弧,终点为起点右侧100距离。
<path d="M 50 650 a 1 2 0 0 0 100 0" stroke="blue" stroke-width="5" fill="none"/>
2.顺时针旋转30°
<path d="M 170 650 a 1 2 30 0 0 100 0" stroke="blue" stroke-width="5" fill="none"/>
3.优弧和劣弧
下面的优弧和劣弧都是按逆时针画的
优弧
<path d="M 300 650 a 70 100 0 1 0 100 0" stroke="blue" stroke-width="5" fill="none"/>
劣弧
<path d="M 450 650 a 70 100 0 0 0 100 0" stroke="blue" stroke-width="5" fill="none"/>
4.顺时针画弧
<path d="M 600 650 a 1 2 0 0 1 100 0" stroke="blue" stroke-width="5" fill="none"/>
以上就是SVG中<path>标签所有命令的用法总结,希望能有所帮助。
写在最后
这是我在稀土掘金发过的文章,稀土掘金的个人主页为峰兄兄 的个人主页 - 动态 - 掘金,两边都会更新,那边一般会早个几天。欢迎大家关注~
文章中的所有图都是我运行自己练习时的代码截的图,原理图也是在截图的基础上,在画图工具中编辑的,希望能得到更多人的认可,也希望能尊重我的劳动成果,未经许可不要转载哦~
一次搞懂-JavaScript 模块化详解
作者:九旬
来源:SegmentFault 思否社区
模块化的意义
将代码拆分成独立的块,然后再把这些块使用模块模式连接起来实现不同的功能。
就像小时候玩的拼图一样,不同的拼图组合在一起就可以拼成任意的形状。
这种模式的背后思想也很简单:把逻辑分块、各自封装,相互独立,同时自行决定引入执行那些外部模块以及暴露自身的那些模块。
这个基本的思想是所有的 JavaScript 模块系统的基础。
https://github.com/AnsonZnl/JS-Modules-Sample
模块化的好处
-
避免命名冲突(减少命名空间污染) -
更好的分离, 按需加载 -
更高复用性 -
高可维护性
JS 中常见的模块
IIFE 模式:匿名函数自调用(闭包)
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
console.log(myModule.get()); // output-data(获取内部数据)
myModule.set("new data"); // 设置内部数据
console.log(myModule.data); //output-undefined (不能访问模块内部数据)
myModule.data = "xxxx"; //不是修改的模块内部的data
console.log(myModule.get()); //output-new data 修改后的值
</script>
// module.js文件
(function(window) {
let data = "data";
//获取数据
function get() {
return data;
}
// 修改数据
function set(val) {
data = val;
}
//暴露行为
window.myModule = {
get,
set,
};
})(window);
CommonJS
module.exports = value
或者
exports.xx = value
(exports 是一个导出的对象)
require(xx)
,如果是第三方模块,xxx 为模块名,如果为自定义模块,xxx 为模块的文件路径。
-
所有代码都运行在模块作用域,不会污染全局作用域。 -
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。 -
模块加载的顺序,按照其在代码中出现的顺序。
在 Node 中 安装 uniq 函数。
npm init
npm install uniq --save
// module.js
let arr = [1, 2, 2, 3, 3];
module.exports = {
arr,
};
// app.js
let module1 = require("./module.js");
let uniq = require("uniq");
console.log(uniq(module1.arr)); // [1,2,3]
AMD
// 定义没有依赖的模块
define(function() {
return 模块;
});
// 定义有依赖的模块
define(["module1", "module2"], function(m1, m2) {
return 模块;
});
require(["module1", "module2"], function(m1, m2) {
使用m1 和 m2;
});
<!-- index.html -->
<body>
<!-- 引入require.js并指定js主文件的入口 -->
<script
data-main="main"
src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
></script>
</body>
// main.js
(function() {
require(["module.js"], function(module) {
let currentUrl = module.getUrl();
alert("当前页面的URl:" + currentUrl);
});
})();
// module.js
// 定义模块
define(function() {
let url = window.location.href;
function getUrl() {
return url.toUpperCase();
}
// 暴露模块
return {
getUrl,
};
});
CMD
-
导入:define(function(require, exports, module){}) -
导出:define(function(){return '值'})
// main.js
define(function(require, exports, module) {
var moduleA = require("./module.js");
alert(moduleA.a); // 打印出:hello world
});
// module.js
define(function(require, exports, module) {
exports.a = "hello world";
});
<body>
<script
data-main="main"
src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
></script>
</body>
UMD
-
先判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块; -
再判断是否支持 Node.js 模块格式(exports 是否存在),存在则使用 Node.js 模块格式; -
前两个都不存在,则将模块公开到全局(window 或 global)
(function(root, factory) {
if (typeof define === "function" && define.amd) {
//AMD
define(["jquery"], factory);
} else if (typeof exports === "object") {
//Node, CommonJS之类的
module.exports = factory(require("jquery"));
} else {
//浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery);
}
})(this, function($) {
//方法
function myFuncA() {} // 私有方法,因为没有返回
function myFuncB() {} // 公共方法,因为返回了
//暴露公共方法
return {
myFuncB,
};
});
ES6 Module
-
按需加载(编译时加载) -
import 和 export 命令只能在模块的顶层,不能在代码块之中(如:if 语句中),import()语句可以在代码块中实现异步动态按需动态加载
-
导入: import {modules1,modules1,} from '模块路径'
-
导出: export
或者export default
-
动态导入: import('模块路径').then(..)
<!-- 揺树(tree-shaking) -->
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save @babel/polyfill
# 然后运行
npx babel-node main.js
// modules/double.js
let mes = "Hello Modules for double";
function sum(value) {
return `${mes} - ${value * 2}`;
}
export default {
mes,
sum,
};
// main.js
import module from "./modules/double";
console.log(module.sum(10)); // Hello Modules for double - 20
-
和 CommonJS 的区别: -
CommonJS 模块输出的是一个值得拷贝,ES6 模块输出的是值的引用 -
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口 -
CommonJS 模块的 require()是同步加载模块,ES6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段。
浏览器和服务器目前的支持不是很好,现阶段使用需要借助一些工具( Babel )。
-
浏览器支持:在新版本的浏览器(如 Chrome)中可以使用 <script type="module" ></script>
写法 -
服务器支持(Node)有两种模式,分别是 ES6 模块和 CommonJS。 -
从 Node.js v13.2 开始,默认支持 ES6 模块,但是需要采用 .mjs
为后缀名、或者在package.json
中修改type
字段为module
(推荐) -
使用 CommonJS 的话需要以 .cjs
为后缀,也可以设置package.json
中修改type
字段为commonjs
(推荐)。
总结
-
CommonJS 规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了 AMD CMD 解决方案。 -
AMD 规范在浏览器环境中异步加载模块,而且可以并行加载多个模块。不过,AMD 规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅。 -
CMD 规范与 AMD 规范很相似,都用于浏览器编程,依赖就近,延迟执行,可以很容易在 Node.js 中运行。不过,依赖 SPM 打包,模块的加载逻辑偏重 -
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
以上是关于SVG路径<Path>标签详解,一次搞懂所有命令参数的主要内容,如果未能解决你的问题,请参考以下文章