css动画效果和canvas

2D转换

css3转换

CSS3 转换可以对元素进行移动、缩放、转动、拉长或拉伸。

工作原理

转换的效果是让某个元素改变形状,大小和位置。

您可以使用 2D 或 3D 转换来转换您的元素。

2D变换方法

  • translate()
  • rotate()
  • scale()
  • skew()
  • matrix()

translate()方法

translate()方法,根据左(X轴)和顶部(Y轴)位置给定的参数,从当前元素位置移动。

style>
  #trans{
    height: 200px;
    width: 200px;
    background-color: red;
    transform: translate(100px);
  }
</style>
<body>
  <div id="trans">2d效果转换</div>
</body>

rotate()方法

rotate()方法,在一个给定度数顺时针旋转的元素。负值是允许的,这样是元素逆时针旋转。

 #trans{
    height: 200px;
    width: 200px;
    background-color: red;
    transform: translate(100px);
    transform: rotate(180deg);//deg表示角度
  }
</style>
<body>
  <div id="trans">2d效果转换</div>
</body>

scale方法

scale()方法,该元素增加或减少的大小,取决于宽度(X轴)和高度(Y轴)的参数:

 #scale{
    height: 100px;
    width: 100px;
    background-color: blue;
    transform: scale(2,2);
    margin: auto;
  }
<div id="scale">放大缩小</div>

scale(2,3)转变宽度为原来的大小的2倍,和其原始大小3倍的高度。

tips:scale()中参数为-1时,图像反向

skew()方法

语法

transform:skew(<angle [,<angle>]>);

包含两个参数值,分别表示X轴和Y轴倾斜的角度,如果第二个参数为空,则默认为0,参数为负表示向相反方向倾斜。

  • skewX();表示只在X轴(水平方向)倾斜。
  • skewY();表示只在Y轴(垂直方向)倾斜。
   #skew{
    transform: skew(30deg,20deg);
  }
 <div id="skew">倾斜</div>

matrix()方法

matrix()方法和2D变换方法合并成一个。

matrix 方法有六个参数,包含旋转,缩放,移动(平移)和倾斜功能。

 #matrix{
    transform:matrix(0.866,0.5,-0.5,0.866,0,0);
  }
<div id="matrix">matrix</div>

matrix的参数表示matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() )

matrix()不支持角度值deg

所有2D转换方法

函数描述
matrix(n,n,n,n,n,n)定义 2D 转换,使用六个值的矩阵。
translate(x,y)定义 2D 转换,沿着 X 和 Y 轴移动元素。
translateX(n)定义 2D 转换,沿着 X 轴移动元素。
translateY(n)定义 2D 转换,沿着 Y 轴移动元素。
scale(x,y)定义 2D 缩放转换,改变元素的宽度和高度。
scaleX(n)定义 2D 缩放转换,改变元素的宽度。
scaleY(n)定义 2D 缩放转换,改变元素的高度。
rotate(angle)定义 2D 旋转,在参数中规定角度。
skew(x-angle,y-angle)定义 2D 倾斜转换,沿着 X 和 Y 轴。
skewX(angle)定义 2D 倾斜转换,沿着 X 轴。
skewY(angle)定义 2D 倾斜转换,沿着 Y 轴。

3D转换

CSS3 允许您使用 3D 转换来对元素进行格式化。

在本章中,您将学到其中的一些 3D 转换方法:

  • rotateX()
  • rotateY()

rotate()方法

rotateX()方法,围绕其在一个给定度数X轴旋转的元素。

  #rotate{
    transform: rotateX(120deg);
  }
  <div id="rotate">3dX旋转</div>

rotateY()方法,围绕其在一个给定度数Y轴旋转的元素。

 #rotateY{
    transform: rotateY(120deg);
  }
  <div id="rotateY">3d旋转2</div>

转换属性

属性描述CSS
transform向元素应用 2D 或 3D 转换。3
transform-origin允许你改变被转换元素的位置。3
transform-style规定被嵌套元素如何在 3D 空间中显示。3
perspective规定 3D 元素的透视效果。3
perspective-origin规定 3D 元素的底部位置。3
backface-visibility定义元素在不面对屏幕时是否可见。3

3D转换方法

函数描述
matrix3d(n,n,n,n,n,n, n,n,n,n,n,n,n,n,n,n)定义 3D 转换,使用 16 个值的 4x4 矩阵。
translate3d(x,y,z)定义 3D 转化。
translateX(x)定义 3D 转化,仅使用用于 X 轴的值。
translateY(y)定义 3D 转化,仅使用用于 Y 轴的值。
translateZ(z)定义 3D 转化,仅使用用于 Z 轴的值。
scale3d(x,y,z)定义 3D 缩放转换。
scaleX(x)定义 3D 缩放转换,通过给定一个 X 轴的值。
scaleY(y)定义 3D 缩放转换,通过给定一个 Y 轴的值。
scaleZ(z)定义 3D 缩放转换,通过给定一个 Z 轴的值。
rotate3d(x,y,z,angle)定义 3D 旋转。
rotateX(angle)定义沿 X 轴的 3D 旋转。
rotateY(angle)定义沿 Y 轴的 3D 旋转。
rotateZ(angle)定义沿 Z 轴的 3D 旋转。
perspective(n)定义 3D 转换元素的透视视图。

CSS3过度


CSS3中,我们为了添加某种效果可以从一种样式转变到另一个的时候,无需使用Flash动画或JavaScript。

原理

CSS3 过渡是元素从一种样式逐渐改变为另一种的效果。

要实现这一点,必须规定两项内容:

  • 指定要添加效果的CSS属性
  • 指定效果的持续时间。

注意: 如果未指定的期限,transition将没有任何效果,因为默认值是0。

指定的CSS属性的值更改时效果会发生变化。一个典型CSS属性的变化是用户鼠标放在一个元素上时:

实例

div
{
	width:100px;
	height:100px;
	background:red;
	transition-property:width;
	transition-duration:1s;
	transition-timing-function:linear;
	transition-delay:2s;
}
div:hover
{
	width:200px;
}

所有过渡属性

属性描述CSS
transition简写属性,用于在一个属性中设置四个过渡属性。3
transition-property规定应用过渡的 CSS 属性的名称。3
transition-duration定义过渡效果花费的时间。默认是 0。3
transition-timing-function规定过渡效果的时间曲线。默认是 “ease”。3
transition-delay规定过渡效果何时开始。默认是 0。3

CSS3动画


CSS3 可以创建动画,它可以取代许多网页动画图像、Flash 动画和 JavaScript 实现的效果。

@keyframes规则

要创建 CSS3 动画,你需要了解 @keyframes 规则。

@keyframes 规则是创建动画。

@keyframes 规则内指定一个 CSS 样式和动画将逐步从目前的样式更改为新的样式。

CSS3动画

当在 @keyframes 创建动画,把它绑定到一个选择器,否则动画不会有任何效果。

指定至少这两个CSS3的动画属性绑定向一个选择器:

  • 规定动画的名称
  • 规定动画的时长

定义动画

   /* 动画效果创建 */
    @keyframes fade {
      from {
        background: red;
      }

      to {
        background: yellow;
      }
    }

在id选择中使用上面创建的动画

   #animate {
      animation: fade 5s;
    }

案例2

可以使用百分比来定义动画播放的时间戳,或者用from和to

这里推荐使用百分比

  @keyframes fadePercent {
      0%{background: black;}
      25%{background: blue;}
      50%{background: red;}
      100%{background: white;}
    }

案例3

更改渐变的方向和位置

    0%   {background: red; left:0px; top:0px;}
    25%  {background: yellow; left:200px; top:0px;}
    50%  {background: blue; left:200px; top:200px;}
    75%  {background: green; left:0px; top:200px;}
    100% {background: red; left:0px; top:0px;}

动画属性

属性描述CSS
@keyframes规定动画。3
animation所有动画属性的简写属性。3
animation-name规定 @keyframes 动画的名称。3
animation-duration规定动画完成一个周期所花费的秒或毫秒。默认是 0。3
animation-timing-function规定动画的速度曲线。默认是 “ease”。3
animation-fill-mode规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。3
animation-delay规定动画何时开始。默认是 0。3
animation-iteration-count规定动画被播放的次数。默认是 1。3
animation-direction规定动画是否在下一周期逆向地播放。默认是 “normal”。3
animation-play-state规定动画是否正在运行或暂停。默认是 “running”。3

动画函数

简介

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。 根据以上 MDN 的定义,requestAnimationFrame 是浏览器提供的一个按帧对网页进行重绘的 API 。

<style>
.test{
  width: 100px;
  height: 100px;
  background-color: aquamarine;
} 
</style>
<body>
  <div class="test"></div>
</body>
<script>
  const test = document.querySelector(".test");
let i = 0;
function animation() {
  if (i > 200) return;
  test.style.marginLeft = `${i}px`;
  window.requestAnimationFrame(animation);
  i++;
}
window.requestAnimationFrame(animation);
</script>

上面的代码 1s 大约执行 60 次,因为一般的屏幕硬件设备的刷新频率都是 60Hz,然后每执行一次大约是 16.6ms。使用 requestAnimationFrame 的时候,只需要反复调用它就可以实现动画效果。

同时 requestAnimationFrame 会返回一个请求 ID,是回调函数列表中的一个唯一值,可以使用 cancelAnimationFrame 通过传入该请求 ID 取消回调函数。

const test = document.querySelector(".test");
    let i = 0;
    let requestId;
    function animation() {
      test.style.marginLeft = `${i}px`;
      requestId = requestAnimationFrame(animation);
      console.log(requestId);
      i++;
      if (i > 200) {
        cancelAnimationFrame(requestId);
      }
    }
    window.requestAnimationFrame(animation);

但是使用setTimeout要比动画函数要卡顿许多,所以尽量使用动画函数制作动画。

3D动画

3D转换属性

属性描述
transform向元素应用 2D 或 3D 转换。
transform-origin允许你改变被转换元素的位置。
transform-style规定被嵌套元素如何在 3D 空间中显示。
perspective规定 3D 元素的透视效果。
perspective-origin规定 3D 元素的底部位置。
backface-visibility定义元素在不面对屏幕时是否可见。
函数描述
matrix3d(n,n,n,n,n,n, n,n,n,n,n,n,n,n,n,n)定义 3D 转换,使用 16 个值的 4x4 矩阵。
translate3d(x,y,z)定义 3D 转化。
translateX(x)定义 3D 转化,仅使用用于 X 轴的值。
translateY(y)定义 3D 转化,仅使用用于 Y 轴的值。
translateZ(z)定义 3D 转化,仅使用用于 Z 轴的值。
scale3d(x,y,z)定义 3D 缩放转换。
scaleX(x)定义 3D 缩放转换,通过给定一个 X 轴的值。
scaleY(y)定义 3D 缩放转换,通过给定一个 Y 轴的值。
scaleZ(z)定义 3D 缩放转换,通过给定一个 Z 轴的值。
rotate3d(x,y,z,angle)定义 3D 旋转。
rotateX(angle)定义沿 X 轴的 3D 旋转。
rotateY(angle)定义沿 Y 轴的 3D 旋转。
rotateZ(angle)定义沿 Z 轴的 3D 旋转。
perspective(n)定义 3D 转换元素的透视视图。

Canvas入门

简介

Canvas 中文名叫 “画布”,是 HTML5 新增的一个标签。

Canvas 允许开发者通过 JS在这个标签上绘制各种图案。

Canvas 拥有多种绘制路径、矩形、圆形、字符以及图片的方法。

Canvas 在某些情况下可以 “代替” 图片。

Canvas 可用于动画、游戏、数据可视化、图片编辑器、实时视频处理等领域。

Canvas和SVG矢量图的区别

CanvasSVG
用JS动态生成元素(一个HTML元素)用XML描述元素(类似HTML元素那样,可用多个元素来描述一个图形)
位图(受屏幕分辨率影响)矢量图(不受屏幕分辨率影响)
不支持事件支持事件
数据发生变化需要重绘不需要重绘

如果需要的数据量比较大,使用Canvas较好,如果对于清晰度有要求并且交互操作比较多,使用SVG比较好

使用canvas

绘制一个直线
<style>
  .printer{
    border: 1px solid #e1e1e1;
  }
</style>
<body>
  <!-- 画布 -->
  <canvas class="printer" width="300px" height="300px">
  </canvas>
</body>
<script>
  let ptr=document.querySelector('.printer')
  let con=ptr.getContext('2d')
  con.moveTo(100,100)//绘制起点
  con.lineTo(200,200)//绘制终点
  con.stroke()//连接起点和终点

  console.log(ptr.width)//300
  console.log(ptr.height)//300
</script>
canvas的宽高

canvas画布的宽高默认为300px,150px。如果要设置宽高,在style中设置是不行的,canvas自带属性widthheight,设置宽高时可以不带单位

<canvas class="printer" width="300" height="300">
  </canvas>

如果用css设置宽高,会出现内容被拉伸的状况

canvas 的默认宽度是300px,默认高度是150px。

  1. 如果使用 css 修改 canvas 的宽高(比如变成 400px * 400px),那宽度就由 300px 拉伸到 400px,高度由 150px 拉伸到 400px。
  2. 使用 js 获取 canvas 的宽高,此时返回的是 canvas 的默认值。
线条的默认宽度和颜色

线条的默认宽度是 1px ,默认颜色是黑色。

但由于默认情况下 canvas 会将线条的中心点和像素的底部对齐,所以会导致显示效果是 2px 和非纯黑色问题。

坐标系

Canvas使用的是W3C坐标系:从上往下,从左往右。

W3C 坐标系数学直角坐标系X轴 是一样的,只是 Y轴 的反向相反。

W3C 坐标系Y轴 正方向向下。

线条的样式设置
  • lineWidth:线的粗细
  • strokeStyle:线的颜色
  • lineCap:线帽:默认: butt; 圆形: round; 方形: square
//修改直线的宽度,颜色
    con.lineWidth = 3;
    con.strokeStyle = "#f00";
    // 修改直线两端样式
    con.lineCap = "round"; // 默认: butt; 圆形: round; 方形: square

beginPath()

在绘制多条线段时,要是设置线条样式,会将其他的不需要样式的线条“污染”

所以使用beginPath()另开一条线段。这样就不会污染了。


    con.moveTo(100, 100); //绘制起点
    con.lineTo(200, 200); //绘制终点
    //修改直线的宽度,颜色
    con.lineWidth = 3;
    con.strokeStyle = "#f00";
    // 修改直线两端样式
    con.lineCap = "round"; // 默认: butt; 圆形: round; 方形: square
    con.stroke(); //连接起点和终点

    con.beginPath();
    con.moveTo(50, 20);
    con.lineTo(150, 20);
    con.strokeStyle='pink'//后面的线段不会影响前面的线段
    con.stroke();

折线

折线和直线一样,只不过需要多段moveTo()lineTo()

  //新画布
    let pub=document.querySelector('.canva')
    let can=pub.getContext('2d')

    // 折线
    can.beginPath()
    can.lineWidth=4
    can.strokeStyle='blue'
    can.moveTo(30,30)
    can.lineTo(100,100)
    can.lineTo(150,100)
    can.lineTo(200,200)
    can.stroke()

矩形

可以根据折线的原理来进行绘制矩形
//矩形
    can.beginPath()
    can.lineWidth=5
    can.strokeStyle='#f00'
    can.moveTo(100,300)
    can.lineTo(300,300)
    can.lineTo(300,400)
    can.lineTo(100,400)
    can.closePath()//闭合线段,或者使用can.lineTo(起始位置),推荐使用closePath()
    can.stroke()
根据canvas提供的rect()方法绘制矩形

strokeStyle:设置描边的属性(颜色、渐变、图案)

strokeRect(x, y, width, height):描边矩形(x和y是矩形左上角起点;width 和 height 是矩形的宽高)

strokeStyle 必须写在 strokeRect() 前面,不然样式不生效。

   //使用strokeRect()绘制矩形
    can.beginPath()
    can.strokeStyle='blue'
    can.lineWidth=3
    can.strokeRect(100,300,200,100)//起点的x,y,宽,高

可以使用fillRect()来填充矩形的颜色,并且此方法和strokeRect()功能差不多,同时fillstyle()可以填充颜色,并且要写在fillRect()上面,不然不会生效

 can.beginPath()
    can.strokeStyle='blue'
    can.fillStyle='pink'
    can.lineWidth=3
    can.fillRect(100,300,200,100)//绘制矩形并进行填充颜色,默认为黑色,可以使用fillStyle进行更改
    // can.strokeRect(100,300,200,100)//起点的x,y,宽,高
同时使用fillRect()strokeRect()

两个方法同时使用可以有边框+填充的效果

 //两个方法同时使用(fillRect()和strokeRect())
    can.beginPath()
    can.strokeStyle='#f00'
    can.strokeRect(100,300,200,100)
    can.fillStyle='#00f'
    can.fillRect(100,300,200,100)
rect()绘制矩形

rect()fillRect() 、strokeRect() 的用法差不多,唯一的区别是:

strokeRect()fillRect() 这两个方法调用后会立即绘制;rect() 方法被调用后,不会立刻绘制矩形,而是需要调用 stroke()fill() 辅助渲染。

   //rect()绘制矩形
    can.beginPath();
    can.strokeStyle = "red";
    can.fillStyle = "pink";
    can.rect(100, 300, 200, 100);
    can.stroke();
    can.fill()

rect()+stroke()=strokeRect()

rect()+fill()=fillRect()

clearRect()清空矩形

语法:

clearRect(x,y,width,height)
    can.clearRect(150,350,50,50)//清空指定区域的矩形,x,y,width,height

可以通过此方法进行画布的清除

can.clearRect(0,0,can.width,can.height)

Canvas多边形制作

多边形的制作

三角形

Canvas 要画多边形,需要使用 moveTo()lineTo()closePath()

 //三角型制作
    con.beginPath(); //新路径生成
    con.lineWidth = 4;
    con.strokeStyle = "blue";
    con.moveTo(10, 10);
    con.lineTo(50, 10);
    con.lineTo(50, 50);
    con.closePath();
    con.stroke();

如果使用lineTo去闭合三角形的话,有时候会不完全闭合,使用closePath()的话就不会产生这种问题。

菱形
  //菱形制作
    con.beginPath()
    con.lineWidth=5
    con.strokeStyle='#f00'
    con.moveTo(120,20)
    con.lineTo(100,50)
    con.lineTo(120,80)
    con.lineTo(140,50)
    con.closePath()
    con.stroke()
圆形

使用arc()方法进行圆形的制作

arc(x, y, r, sAngle, eAngle,counterclockwise)
  • xy: 圆心坐标
  • r: 半径
  • sAngle: 开始角度
  • eAngle: 结束角度
  • counterclockwise: 绘制方向(true: 逆时针; false: 顺时针),默认 false

开始角度和结束角度,都是以弧度为单位。例如 180°就写成 Math.PI ,360°写成 Math.PI * 2 ,以此类推。

在实际开发中,为了让自己或者别的开发者更容易看懂弧度的数值,1°应该写成 Math.PI / 180

  • 100°: 100 * Math.PI / 180
  • 110°: 110 * Math.PI / 180
  • 241°: 241 * Math.PI / 180

注意:绘制圆形之前,必须先调用 beginPath() 方法!!! 在绘制完成之后,还需要调用 closePath() 方法!!!

半圆

在制作圆形的时候,画到180°时进行闭合就是半圆

//半圆制作
    con.beginPath()
    con.lineWidth=3
    con.strokeStyle=`#f00`
    con.arc(500,200,180,0*Math.PI/180,180*Math.PI/180,false)
    con.closePath()
    con.stroke()

如果想让半圆在上方呈现,将最后一个参数改为true

 //上方半圆制作
    con.beginPath()
    con.lineWidth=3
    con.strokeStyle=`#f00`
    con.arc(500,200,180,0*Math.PI/180,180*Math.PI/180,true)
    con.closePath()
    con.stroke()
弧线

可以使用arc()画弧线,选择弧度后,不进行closePath()就可以画出弧线

  //arc()弧线
    con.beginPath()
    con.lineWidth=3
    con.strokeStyle=`#f00`
    con.arc(200,400,180,0*Math.PI/180,30*Math.PI/180,false)
    con.stroke()

arcTo()画弧线

arcTo(cx, cy, x2, y2, radius)
  • cx: 两切线交点的横坐标
  • cy: 两切线交点的纵坐标
  • x2: 结束点的横坐标
  • y2: 结束点的纵坐标
  • radius: 半径

其中,(cx, cy) 也叫控制点,(x2, y2) 也叫结束点。

是不是有点奇怪,为什么没有 x1y1

(x1, y1) 是开始点,通常是由 moveTo() 或者 lineTo() 提供。

arcTo() 方法利用 开始点、控制点和结束点形成的夹角,绘制一段与夹角的两边相切并且半径为 radius 的圆弧

   //arcTo()弧线
    con.moveTo(40, 40);
    con.arcTo(120, 40, 120, 120, 80);//切线交点的x,y;结束点的横纵坐标;半径

    con.stroke();

基本样式

stroke()

stroke()主要是用来描边的

lineWidth

lineWidth用来控制线的宽度,默认是1默认单位为px

strokeStyle

线条样式,可以设置颜色

strokeStyle=颜色值
lineCap

线帽样式,可以设置线两端的样式

lineCap='属性值'
  • butt: 默认值,无线帽
  • square: 方形线帽
  • round: 圆形线帽

使用 squareround 的话,会使线条变得稍微长一点点,这是给线条增加线帽的部分,这个长度在日常开发中需要注意。

线帽只对线条的开始和结尾处产生作用,对拐角不会产生任何作用。

拐角样式lineJoin
lineJoin = '属性值'

属性值包括:

  • miter: 默认值,尖角
  • round: 圆角
  • bevel: 斜角
虚线样式
setLineDash([])

里面的参数是一个数组了类型。

可以传入1-3个以上的参数

cxt.setLineDash([10]) // 只传1个参数,实线与空白都是 10px
cxt.setLineDash([10, 20]) // 2个参数,此时,实线是 10px, 空白 20px
  cxt.setLineDash([10, 20, 5]) // 传3个以上的参数,此例:10px实线,20px空白,5px实线,10px空白,20px实线,5px空白 ……

此外,还可以始终 cxt.getLineDash() 获取虚线不重复的距离;

cxt.lineDashOffset 设置虚线的偏移位。

填充

使用fill()进行填充图形,默认填充为黑色。使用fillStyle来设置填充颜色。

非零环绕填充

在使用 fill() 方法填充时,需要注意一个规则:非零环绕填充

在使用 moveTolineTo 描述图形时,如果是按顺时针绘制,计数器会加1;如果是逆时针,计数器会减1。

当图形所处的位置,计数器的结果为0时,它就不会被填充。

比如

 // 外层矩形
  cxt.moveTo(50, 50)
  cxt.lineTo(250, 50)
  cxt.lineTo(250, 250)
  cxt.lineTo(50, 250)
  cxt.closePath()

  // 内层矩形
  cxt.moveTo(200, 100)
  cxt.lineTo(100, 100)
  cxt.lineTo(100, 200)
  cxt.lineTo(200, 200)
  cxt.closePath()
  cxt.fill()

外层矩形是顺时针绘制的,内层矩形是逆时针绘制的,顺时针绘制的大矩形里面的计数器值为1,而里面又是由一个逆时针绘制的小矩形,小矩形里面的值是-1而加上外层矩形里面的计数器值1,抵消为0所以内层矩形的里面不会被填充。

canvas文本

样式font

canvas也可以和css一样进行字体的设置

cxt.font = 'font-style font-variant font-weight font-size/line-height font-family'

如果需要设置字号 font-size,需要同时设置 font-family

cxt.font = '30px 宋体'
描边storkText()

使用 strokeText() 方法进行文本描边

语法:

strokeText(text, x, y, maxWidth)
  • text: 字符串,要绘制的内容
  • x: 横坐标,文本左边要对齐的坐标(默认左对齐)
  • y: 纵坐标,文本底边要对齐的坐标
  • maxWidth: 可选参数,表示文本渲染的最大宽度(px),如果文本超出 maxWidth 设置的值,文本会被压缩。
 //文本
  con.font='40px 宋体'
  con.strokeText('hello',10,50)
strokeStyle

strokeStyle设置字体颜色

fillText填充文本
fillText(text,x,y,maxWidth)
  con.fillText('hello',20,60)
获取文本长度

使用measureText()获取文本的长度,单位是px

console.log(con.measureText('hello').width)//100
水平对齐

使用textAlign对齐文本

使用 textAlign 属性可以设置文字的水平对齐方式,一共有5个值可选

  • start: 默认。在指定位置的横坐标开始。
  • end: 在指定坐标的横坐标结束。
  • left: 左对齐。
  • right: 右对齐。
  • center: 居中对齐。
垂直对齐textBaseline

使用 textBaseline 属性可以设置文字的垂直对齐方式。

textBaseline 可选属性:

  • alphabetic: 默认。文本基线是普通的字母基线。
  • top: 文本基线是 em 方框的顶端。
  • bottom: 文本基线是 em 方框的底端。
  • middle: 文本基线是 em 方框的正中。
  • hanging: 文本基线是悬挂基线。

canvas图片

渲染图片

渲染图片的方式有2中,一种是在JS里加载图片再渲染,另一种是把DOM里的图片拿到 canvas 里渲染

JS渲染:

drawImage(image,dx,dy)
  • image: 要渲染的图片对象。

  • dx: 图片左上角的横坐标位置。

  • dy: 图片左上角的纵坐标位置。

     //JS在canvas上渲染图片
      //创建图像
      const image=new Image()
      //初始化路径
      image.src='../4.(工具)css3动画效果/src/loading-Home.gif'
      //加载图片
      image.onload=()=>{
        //在画布上加载图像
        con.drawImage(image,30,30)
      }
    

DOM渲染:

 <canvas width="800px" height="500"></canvas>
  <img src="../4.(工具)css3动画效果/src/plane.svg" alt="" srcset="" class="img">
  
  //DOM在canvas上渲染图片
  let image=document.querySelector('.img')
  con.drawImage(image,30,30)

DOM渲染时,将img标签设置display:none防止它影响canvas

设置图片尺寸

drawImg(img,dx,dy,dw,dh)

dw:宽度

dh:高度

 let image=document.querySelector('.img')
  con.drawImage(image,30,30,200,200)

截取图片

截图图片同样使用drawImage() 方法,只不过传入的参数数量比之前都多,而且顺序也有点不一样了。

drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

以上参数缺一不可

  • image: 图片对象
  • sx: 开始截取的横坐标
  • sy: 开始截取的纵坐标
  • sw: 截取的宽度
  • sh: 截取的高度
  • dx: 图片左上角的横坐标位置
  • dy: 图片左上角的纵坐标位置
  • dw: 图片宽度
  • dh: 图片高度
  //截取图片
  con.drawImage(image,40,40,100,100,30,30,200,300)

canvas变形

状态保存和恢复

在变形之前,两个很重要的方法

save()保存当前canvas画布的状态

restore()恢复到之前保存过的状态

Canvas 状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。可以调用任意多次 save方法。每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。

 //创建一个新的路径
  con.beginPath()
  con.fillStyle='#f00'
  //画一个高宽为200的矩形,并在画布中间呈现
  con.fillRect(300,150,200,200)
  con.fill()
  con.save()//保存当前状态,默认状态

save()和restore()方法只会在有效范围内生效,它是绘制状态的存储器,并不是画布内容的存储器。它是基于状态记录的。
Canvas Context维持着绘制状态的堆栈。区分绘制状态:

  • 当前矩阵变换例如:平移translate(),缩放scale(),以及旋转rotate()等
  • 剪切区域clip()
  • 以下属性值: strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline。
  • 路径和位图不是绘图状态的一部分,使用save()和restore()不会生效。路径是持久的,只能使用beginPath()方法重置,位图是画布的属性,而非上下文。
  • context.save()将当前状态压入堆栈。context.restore()弹出堆栈上的顶级状态,将上下文恢复到该状态。

translating

语法

con.translate(dx,dy)

dx指横坐标偏移量,dy指的是纵坐标的偏移量

 //加载上一次的状态
  con.restore()
  //在上一次状态中改变了位置和颜色
  con.fillStyle='#0f0'
  con.translate(100,-100)//向右移动100.向上移动100
  con.fillRect(300,150,200,200)

rotate方法

rotate()表示旋转,默认旋转的圆心为圆点,如果要改变圆点,需要借助translate()

 con.restore()
  con.rotate((Math.PI*2)/9)//旋转60度
  con.fillRect(300,150,200,200)

通过rotate()进行中心旋转

//第二块画布
  let canva=document.querySelector('.canva')
  let print=canva.getContext('2d')
  print.save()//保存画布的初始状态

  print.translate(250,250)//圆点位移
  print.beginPath()
  print.fillStyle='#0f0'
  print.rotate((Math.PI*2)/6)
  print.fillRect(-25,-25,50,50)

scale方法

scale方法表示缩放

  • scale(x, y)

    scale方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。默认值为 1,为实际大小。

画布初始情况下,是以左上角坐标为原点的第一象限。如果参数为负实数,相当于以 x 或 y 轴作为对称轴镜像反转(例如,使用translate(0,canvas.height); scale(1,-1); 以 y 轴作为对称轴镜像反转,就可得到著名的笛卡尔坐标系,左下角为原点)。

默认情况下,canvas 的 1 个单位为 1 个像素。举例说,如果我们设置缩放因子是 0.5,1 个单位就变成对应 0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为 2.0 时,1 个单位就对应变成了 2 像素,绘制的结果就是图形放大了 2 倍。

  print.restore()//恢复初始态
  print.font='36px 宋体'
  print.scale(2,2)
  print.fillText('hello',50,50)

像素操作

imageData对象

图像本质是由像素构成的,在canvas下的图像像素都保存在imageData对象下。

ImageData() 构造函数返回一个新的实例化的 ImageData 对象, 此对象由给定的类型化数组和指定的宽度与高度组成

new ImageData([array], width, height);

/*
array
	包含图像隐藏像素的 Uint8ClampedArray 数组。如果数组没有给定,指定大小的黑色矩形图像将会被创建。
width
	无符号长整型(unsigned long)数值,描述图像的宽度。
height
    无符号长整型(unsigned long)数值,描述图像的高度。
*/

其中的属性都是只读属性,不可以改变

创建ImageData对象

使用createImageData()方法创建一个ImageData对象

var myImageData = ctx.createImageData(width, height);

创建一个具体尺寸的ImageData对象,所有像素被预设为透明黑

或者可以这样创建

var myImageData = ctx.createImageData(anotherImageData);

得到像素数据

使用getImageData()方法来获取指定区域的像素数据,它返回的也是一个ImageData()对象

var myImageData = ctx.getImageData(left, top, width, height);

实例

//鼠标移入事件
    canvas.addEventListener('mousemove',e=>{
      //获取当前像素位置(鼠标移入的位置)
      let x=e.offsetX
      let y=e.offsetY
      let pixel=con.getImageData(x,y,1,1)//获取鼠标移入位置的一像素对象,并存到pixel变量
      //设置显示的位置
      hoverDiv.style.background=`rgba(${pixel.data[0]}, ${pixel.data[1]}, ${pixel.data[2]}, 1)`
      hoverDiv.textContent=`rgba(${pixel.data[0]}, ${pixel.data[1]}, ${pixel.data[2]}, 1)`
    })

    canvas.addEventListener('click',e=>{
        //获取当前像素位置(鼠标点击的位置)
        let x=e.offsetX
      let y=e.offsetY
      let pixel=con.getImageData(x,y,1,1)//获取鼠标点击位置的一像素对象,并存到pixel变量
      //设置显示的位置
      clickDiv.style.background=`rgba(${pixel.data[0]}, ${pixel.data[1]}, ${pixel.data[2]}, 1)`
      clickDiv.textContent=`rgba(${pixel.data[0]}, ${pixel.data[1]}, ${pixel.data[2]}, 1)`
    })

写入像素数据

使用putImageData()进行写入

ctx.putImageData(myImageData, dx, dy);

dx 和 dy 参数表示你希望在场景内左上角绘制的像素数据所得到的设备坐标。

 //创建自己的像素对象
     let myImageData=con.createImageData(0,0,100,100)
    //将创建的像素对象填充到画布
    con.putImageData(myImageData,100,100)
ctx.putImageData(imagedata, 
                 dx, dy, //图片相对原点位置
                 X, Y, //裁剪起始坐标
                 W, H//裁剪大小
                );
//图片填充
  img.onload=()=>{
    ctx.drawImage(img,0,0,800,500)

      //用像素提取图像
   let myImageData=ctx.getImageData(0,0,800,500)
   //将提取到的图像放到画布
  ctx.putImageData(myImageData,0,500,400,250,100,100)
  }

图像灰度处理

灰度算法 const lm =0.299r + 0.587g+ 0.114b;

  //图像的灰度处理
      //获取像素对象
      let imageDt = con.getImageData(0, 0, 800, 500);
      for (let i = 0; i < imageDt.data.length; i += 4) {
        //解构赋值,将每个rgb值赋值到常量中
        let [r, g, b] = [
          imageDt.data[i],
          imageDt.data[i + 1],
          imageDt.data[i + 2],
        ];
        //灰度处理
        let lm = r * 0.299 + g * 0.587 + b * 0.114;
        //再将灰度的rgb传回去
        imageDt.data[i] = lm;
        imageDt.data[i + 1] = lm;
        imageDt.data[i + 2] = lm;
      }

      con.putImageData(imageDt, 0, 500, 0, 0, 800, 500);

图像马赛克处理

let [width, height] = [canvas.width, canvas.height];
    console.log(width, height);
    const size = 20; //马赛克色块尺寸
    let img = new Image();
    img.src = "../../../src/命脉.png";

    img.onload = () => {
      ctx.drawImage(img, 0, 0, 800, 500);

      let imageDt = ctx.getImageData(0, 0, 800, 500);

      //行列遍历像素
      for (let y = 0; y < 500; y += size) {
        for (let x = 0; x < 800; x += size) {
          const i = (y * 800 + x) * 4;
          const [r, g, b] = [
            imageDt.data[i],
            imageDt.data[i + 1],
            imageDt.data[i + 2],
          ];
          ctx.fillStyle = `RGB(${r},${g},${b})`;
          ctx.fillRect(x, y, size, size);
        }
      }
    };

合成和剪裁

透明度

ctx.globalAlpha=value

值在0-1之间,设置透明度

 ctx.fillStyle = "#000";
    ctx.globalAlpha = 0.2;
    for (i = 0; i < 7; i++) {
      ctx.beginPath();
      ctx.arc(250, 250, 10 + 10 * i, 0, Math.PI * 2, true);
      ctx.fill();
    }
    ctx.restore();

全局合成

全局合成指已绘图像(source)和将绘图像(destination)的合成方式

ctx.globalCompositeOperation=type

/* type值
 * source-atop         新图形只在与现有画布内容重叠的地方绘制
 * source-in           新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。
 * source-out          在不与现有画布内容重叠的地方绘制新图形。
 * source-over 默认     这是默认设置,并在现有画布上下文之上绘制新图形。
 * destination-atop    现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的
 * destination-in      现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的
 * destination-out     现有内容保持在新图形不重叠的地方。
 * destination-over    在现有的画布内容后面绘制新的图形。
 * lighter             两个重叠图形的颜色是通过颜色值相加来确定的。
 * copy                只显示新图形。
 * xor				   图像中,那些重叠和正常绘制之外的其他地方是透明的
 * ...
 * */
sourcedestination
atop已绘图像顶部显示将绘图像将绘图像顶部显示已绘图像
in已绘图像内部显示将绘图像将绘图像内部显示已绘图像
out已绘图像外部显示~将绘图像内部显示~
over将绘图像覆盖已绘图像显示已绘图像覆盖将绘图像显示
 ctx.fillStyle='#f0f'
 ctx.fillRect(0,0,300,300)
 
 ctx.beginPath()
 ctx.globalAlpha=0.7
 ctx.fillStyle = 'green';
//  ctx.globalCompositeOperation="source-atop"
//  ctx.globalCompositeOperation="source-in"
//  ctx.globalCompositeOperation="source-out"
//  ctx.globalCompositeOperation="source-over"
//  ctx.globalCompositeOperation="destination-atop"
//  ctx.globalCompositeOperation="destination-in"
//  ctx.globalCompositeOperation="destination-out"
//  ctx.globalCompositeOperation="destination-over"
// ctx.globalCompositeOperation="xor"
// ctx.globalCompositeOperation="lighter"
// ctx.globalCompositeOperation="copy"

 ctx.arc(300,300,100,0,Math.PI*2)
 ctx.fill()

clip()裁剪

clip()作用是将当前图形作为一个画布。画在上面的图形,其突出的部分不会显示。

ctx.fillStyle='blue'
ctx.arc(300,300,200,0,Math.PI*2,true)
ctx.fill()
ctx.clip()

ctx.fillStyle='red'
ctx.fillRect(300,300,200,200)

运动动画

动画

使用setTimeoutsetIntervalRequestAnimationFrame来进行动画创作

setTimeOut(fn,time) 和setInterval(fn,time)

优点:使用方便,动画的时间间隔可以自定义。

缺点:隐藏浏览器标签后,会依旧运行,造成资源浪费。与浏览器刷新频率不同步。

requestAnimationFrame(fn)

优点:性能更优良。隐藏浏览器标签后,便不会运行。与浏览器刷新频率同步。

缺点:动画的时间间隔无法自定义

//小球和画布的创建
 //创建一个画布的长宽
    const [width, height] = [canvas.width, canvas.height];

    class ball {
      //构造函数,构造小球
      constructor(x, y, r, color, vx, vy) {
        this.x = x;
        this.y = y;
        this.r = r;
        this.color = color;
        this.vx = vx;
        this.vy = vy;
      }

      render(ctx) {
        //每次渲染之前清空画布
        ctx.clearRect(0, 0, width, height);
        ctx.save();

        //画布中线创建
        ctx.beginPath();
        ctx.moveTo(width / 2, 0);
        ctx.lineTo(width / 2, height);
        ctx.closePath();
        ctx.stroke();

        //碰撞线创建
        ctx.beginPath();
        ctx.moveTo(0, 0);
        ctx.lineTo(0, height);
        ctx.closePath();
        ctx.stroke();

        ctx.beginPath();
        ctx.moveTo(width, 0);
        ctx.lineTo(width, height);
        ctx.closePath();
        ctx.stroke();

        //小球创建
        ctx.beginPath();
        ctx.globalAlpha = 0.5;
        ctx.fillStyle = `color`;
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true);
        ctx.fill();
      }
    }

    const flexBall = new ball(30, 30, 30, "black", 30, 30);
    flexBall.render(ctx);

动画的创建

//使用setInterval()
    // setInterval(()=>{
    //   //小球做往复运动
    //   if(flexBall.x+flexBall.r>=width||(flexBall.vx<0&&flexBall.x-flexBall.r<=0)){
    //     flexBall.vx=flexBall.vx*(-1)
    //   }
    //   flexBall.x+=flexBall.vx
    //   flexBall.render(ctx)
    //   },100)

    //使用动画函数
    animationFun();
    function animationFun() {
      if (
        flexBall.x + flexBall.r >= width ||
        (flexBall.vx < 0 && flexBall.x - flexBall.r <= 0)
      ) {
        flexBall.vx = flexBall.vx * -1;
      }
      flexBall.x += flexBall.vx;
      flexBall.render(ctx);
      requestAnimationFrame(animationFun);
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值