本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!javascript
基本代码以下,全部示例在此canvas实现前端
<style>
canvas{
border: 1px solid #000;
}
</style>
<canvas width="600" height="500" id="c1"></canvas>
<script> let canvas=document.getElementById("c1"); let ctx=canvas.getContext("2d"); // 示例。。。 </script>
复制代码
基本的图形变换包括位移、旋转、缩放。在canvas中,这些操做都是基于坐标系原点进行操做的。在复杂多图形处理中,不一样的图形应用的变换多种多种,这样就有可能产生混乱,所以Canvas中提供save和restore方法,实现坐标系、颜色设置等上下文的隔离和还原。java
translate(x, y)
: 移动 canvas 的原点到指定的位置。即移动的是坐标原点。ctx.beginPath();
// 将canvas坐标系原点移动到 x,y
ctx.translate(origin.x,origin.y);
ctx.arc(0,0,20,0,2*Math.PI);
ctx.fillStyle="green";
ctx.fill();
ctx.beginPath();
ctx.rect(-canvas.width/2 +100,-canvas.height/2+50,200,100);
ctx.strokeStyle="red";
ctx.stroke();
复制代码
rotate(angle)
:顺时针方向的,以弧度为单位旋转坐标轴,旋转的中心是坐标原点。canvas
旋转(坐标原点)后端
let rotateTest=function(){
ctx.beginPath();
ctx.rotate(Math.PI/180*30);
ctx.rect(0,0,320,180);
ctx.fillStyle="green";
ctx.fill();
}
rotateTest();
复制代码
let rotateTest2=function(){
// 位移原点,旋转时以原点旋转
ctx.translate(100, 100);
ctx.beginPath();
ctx.rect(0, 0, 320, 180);
ctx.fillStyle = "red";
ctx.fill();
ctx.beginPath();
ctx.rotate(Math.PI/180*32);
ctx.rect(0,0,320,180);
ctx.fillStyle="green";
ctx.fill();
}
rotateTest2();
复制代码
scale(x, y)
经过增减图形在 canvas 中的像素数目,对形状(位图)进行缩小或者放大。scale方法。x,y分别表示横轴和纵轴的缩放,正值。小于1表示缩小,大于1表示放大,1为原始比例。数组
默认状况下,canvas 的 1 单位就是 1 个像素。举例说,若是咱们设置缩放因子是 0.5,1 个单位就变成对应 0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为 2.0 时,1 个单位就对应变成了 2 像素,绘制的结果就是图形放大了 2 倍。markdown
能够看做缩放是整个画布坐标系的缩放app
let scaleTest=function(){
ctx.beginPath();
ctx.strokeStyle="green";
ctx.lineWidth=3;
ctx.strokeRect(0,0,200,100);
// 缩放x或y轴
ctx.scale(2,1);
ctx.scale(1,2);
ctx.scale(2, 2);
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.lineWidth = 3;
ctx.strokeRect(0, 0, 200, 100);
}
scaleTest();
复制代码
以下,利用勾股定理求距离dom
let getDistance=function(x1,y1,x2,y2){
return Math.sqrt(Math.abs((x1 - x2) * (x1 - x2))*Math.abs((y1-y2)*(y1-y2)))
}
复制代码
数学中sin-正弦、cos-余弦、tan-正切的关系以下图:函数
Math.sin(x)
返回一个 -1 到 1 之间的数值,表示给定角度(单位:弧度)的正弦值。Math.cos(x)
返回一个 -1 到 1 之间的数值,表示角度(单位:弧度)的余弦值。Math.atan2(y,x)
返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值),返回值-pi 到 pi 之间,点x,y的偏移角度。Math.atan(y/x)
返回的弧度在一三或二四象限是相同的,没法区分。Math.tan(x)
返回一个角(弧度)的正切值。`// sin cos atan2
let sincosatan2Test=function(){
let p={
x:100,
y:100,
}
let alpha=Math.atan2(p.x,p.y);
console.log(`坐标${p.x},${p.y}的弧度值:${alpha}`);
console.log(`坐标${p.x},${p.y}的角度:${alpha*180/Math.PI}度`);
let anglePI_sin=Math.sin(Math.PI);
let anglehalfPI_sin=Math.sin(Math.PI/2);
let angle2PI_sin = Math.sin(Math.PI*2);
let angle1000_sin = Math.sin(1000);
console.log("PI的sin:"+anglePI_sin);
console.log("1/2PI的sin:"+anglehalfPI_sin);
console.log("2*PI的sin:"+angle2PI_sin);
console.log("1000的sin:"+angle1000_sin);
let anglePI_cos = Math.cos(Math.PI);
let anglehalfPI_cos = Math.cos(Math.PI / 2);
let angle2PI_cos = Math.cos(Math.PI * 2);
let angle1000_cos = Math.cos(1000);
console.log("PI的sin:" + anglePI_sin);
console.log("1/2PI的sin:" + anglehalfPI_sin);
console.log("2*PI的sin:" + angle2PI_sin);
console.log("1000的sin:" + angle1000_sin);
}
sincosatan2Test();
复制代码
在Canvas中,Saving and restoring state是绘制复杂图形时必不可少的操做。
save的做用在于隔离出来一个新的canvas上下文环境,保存以前的状态,能够从新设置新的样式并绘制图形;restore的做用在于恢复上一次的保存的状态,使用旧的样式绘制。
尤为是对于使用了位移、旋转、缩放等效果的状况下,restore能够还原坐标系的状态,防止复杂操做下出现混乱。
save()
和restore()
方法用来保存和恢复Canvas的状态
Canvas的状态就是当前画面应用到的全部样式和变形的一个快照。
Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。
一个绘画状态包括:
当前应用的变形(即移动,旋转和缩放)
strokeStyle
, fillStyle
, globalAlpha
, lineWidth
, lineCap
, lineJoin
, miterLimit
, shadowOffsetX
, shadowOffsetY
, shadowBlur
, shadowColor
, globalCompositeOperation
的值
当前的裁切路径(clipping path)
能够调用任意屡次save方法。(相似数组的push())
每一次调用restore方法,上一个保存的状态就从栈中弹出,全部设定都恢复。(相似数组的pop())。
save和resotre对canvas上下文状态的隔离和管理很是方便,一般写canvas效果能够以下所示:
// 保存以前的状态
ctx.save();
// 样式设置
//...
ctx.restore();//恢复状态
复制代码
以下,使用这个过程:画一个正方形,保存以前的状态并修改颜色绘制,保存以前的状态并修改颜色绘制,恢复状态并绘制,恢复状态并绘制,绘制的一个小例子。
// 状态保存恢复
let statusSaveRestore=function(){
ctx.fillRect(0, 0, 150, 150); // 使用默认设置绘制一个矩形
ctx.save(); // 保存默认状态
ctx.fillStyle = 'red' // 在原有配置基础上对颜色作改变
ctx.fillRect(15, 15, 120, 120); // 使用新的设置绘制一个矩形
ctx.save(); // 保存当前状态
ctx.fillStyle = '#FFF' // 再次改变颜色配置
ctx.fillRect(30, 30, 90, 90); // 使用新的配置绘制一个矩形
ctx.restore(); // 从新加载以前的颜色状态
ctx.fillRect(45, 45, 60, 60); // 使用上一次的配置绘制一个矩形
ctx.restore(); // 加载默认颜色配置
ctx.fillRect(60, 60, 30, 30); // 使用加载的配置绘制一个矩形
}
statusSaveRestore();
复制代码
不使用状态保存和恢复的效果以下:
以下,五角星的五个尖角和5个钝角能够看做从圆心平均分开的10个点,能够由内外两个圆各自包含5个点,给定不一样的内外圆的半径,各个点的坐标就能够经过正余弦求得。
以下,实现五角星的函数代码,还能够修改,防止产生反五角星:
// 画一个五角星
let drawPentagram=function(options){
let ctx=options.ctx;
let origin = {
x: options.x,
y: options.y
}
let lengthScale=options.lengthScale||0.4; // 大于1也是五角星 反五角星
// 五角星长短边
let lengthR = options.lengthR||100;
let shortR = lengthScale* lengthR;
// 五角星的角度 弧度
let starRotate=options.starRotate||0;
let strokeColor=options.strokeColor||"red";
let deg = Math.PI * 2 / 10;
ctx.save();
// 移动画布原点到五角星中心
ctx.translate(origin.x, origin.y);
// 先假设长边角 位于x轴上
// 旋转坐标系,x轴向上,即尖角向上,保证摆正五角星
ctx.rotate(- Math.PI / 2);
ctx.rotate(starRotate);
ctx.beginPath();
//ctx.moveTo(lengthR*Math.cos(0),lengthR*Math.sin(0));
ctx.moveTo(lengthR, 0);
for (let i = 1; i < 10; i++) {
let currDeg = i * deg;
if (i % 2 === 0) { //lengthR
ctx.lineTo(lengthR * Math.cos(currDeg), lengthR * Math.sin(currDeg));
}
else {
ctx.lineTo(shortR * Math.cos(currDeg), shortR * Math.sin(currDeg));
}
}
ctx.closePath();
ctx.strokeStyle = strokeColor;
ctx.stroke();
// 将坐标系旋转放正 旋转的是坐标系,之前已经画好的图形保持不变
// 由于使用了restore,此处的旋转还原能够省略
// ctx.rotate(Math.PI / 2);
ctx.restore();
}
复制代码
drawPentagram({
ctx,
x:canvas.width / 2,
y:canvas.height / 2,
});
复制代码
代码效果以下:
let colorArr=["red","greed","yellow","pink","olive","blue","orange","brown","purple"]
for (let i = 0; i < 10; i++) {
drawPentagram({
ctx,
x: canvas.width*Math.random(),
y: canvas.height*Math.random(),
lengthR:100*Math.random(),
lengthScale: Math.random(),
strokeColor:colorArr[Math.floor(colorArr.length*Math.random())],
starRotate: Math.PI*2* Math.random()
});
}
复制代码
代码效果以下: