canvas中save和restore的理解和使用

canvas中save和restore的理解和使用

理解save和restore不一定总是成对出现的

每个 canvascontext 上下文都包含一个保存绘画状态的栈,以下内容都属于绘画状态

  • 当前的变换矩阵
  • 当前的裁剪区域
  • strokeStylefillStylelineWidthlineCapfonttextAlignshadowOffsetX … 这些属性的当前值

当前路径和当前的位图并不属于绘画状态,当前路径是永久存在的,要清除或者重置只能通过 beginPath 方法,而当前位图是属于 canvas 的属性,而不是 context
context.save() 会把当前的状态推入栈中
context.restore() 会从栈中取出最顶部的状态,context 就还原到取出的状态

<canvas id="canvas" width="500" height="300"></canvas>

<script>
window.addEventListener('load', saveRestore, true)
function saveRestore() {
      
      
  let canvas = document.getElementById('canvas')
  let context = canvas.getContext('2d')
  
  // 绘制了一个红色的矩形
  context.fillStyle = 'red'
  context.shadowOffsetX = 5
  context.shadowOffsetY = 5
  context.shadowBlur = 4
  context.shadowColor = 'rgba(0, 255, 0, 0.3)'
  context.fillRect(20, 20, 50, 150)

  context.save() // 当前状态1保存(红色,绿色阴影5)推入栈中

  // 绘制一个绿色的矩形
  context.fillStyle = 'green'
  context.shadowOffsetX = 10
  context.shadowOffsetY = 10
  context.shadowBlur = 4
  context.shadowColor = 'rgba(255, 0, 0, 0.3)'
  context.fillRect(100, 40, 50, 150)

  context.save() // 当前状态2保存(绿色,红色阴影10)推入栈中
  
  // 绘制一个橘色的矩形
  context.fillStyle = 'orange'
  context.shadowOffsetX = 15
  context.shadowOffsetY = 15
  context.shadowBlur = 4
  context.shadowColor = 'rgba(0, 0, 255, 0.3)'
  context.fillRect(190, 60, 50, 150)

  context.save() // 当前状态3保存(橘色,蓝色阴影15)推入栈中
}
</script>

此时绘制的状态为
在这里插入图片描述
现在通过从栈中取出不同的状态绘制圆

...
context.save() // 当前状态3保存(橘色,蓝色阴影15)推入栈中

context.restore() // 当前取出的是最顶上的状态(状态3)

// 根据以上取出栈中的样式绘制圆
context.beginPath()
context.arc(300, 75, 15, 0, Math.PI * 2, true)
context.fill()

在这里插入图片描述

...
context.save() // 当前状态3保存(橘色,蓝色阴影15)推入栈中

context.restore() // 当前取出的是最顶上的状态(状态3)
context.restore() // 当前取出的是最顶上的状态(状态2)

// 根据以上取出栈中的样式绘制圆
context.beginPath()
context.arc(300, 75, 15, 0, Math.PI * 2, true)
context.fill()

在这里插入图片描述

context.save() // 当前状态3保存(橘色,蓝色阴影15)推入栈中

context.restore() // 当前取出的是最顶上的状态(状态3)
context.restore() // 当前取出的是最顶上的状态(状态2)
context.restore() // 当前取出的是最顶上的状态(状态1)

// 根据以上取出栈中的样式绘制圆
context.beginPath()
context.arc(300, 75, 15, 0, Math.PI * 2, true)
context.fill()

在这里插入图片描述

太阳系

下面看一个小案例好好理解和消化一下吧
请添加图片描述

const WIDTH = 800, SPAN = 40
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.width = WIDTH
canvas.height = WIDTH
canvas.style.background = '#000'

// 轨道
function drawTrack() {
    
    
	for(let i=0; i < 8; i++){
    
    
		ctx.beginPath()
		ctx.arc(WIDTH / 2, WIDTH / 2, (i + 1) * SPAN, 0, 360, false)
		ctx.closePath()
		ctx.strokeStyle = '#fff'
		ctx.stroke()
	}
}
drawTrack()

// 星球
class Star {
    
    
  constructor(x, y, radius, cycle, startColor, endColor) {
    
    
    // 星球坐标
    this.x = x
 	this.y = y
    this.radius = radius // 星球半径
    this.cycle = cycle // 公转周期
    this.color = null // 新建一个渐变颜色空对象
    this.time = 0
    this.startColor = startColor
    this.endColor = endColor
  }
  draw() {
    
    
    ctx.save()
	ctx.translate(WIDTH / 2, WIDTH / 2)
    // rotate 针对的是绘制的图形,以translate的坐标为圆点进行旋转
	ctx.rotate(this.time * (360 / this.cycle) * Math.PI / 180)
	// 画星球
	ctx.beginPath()
	ctx.arc(this.x, this.y, this.radius, 0, 360, false)
	ctx.closePath()
	// 设置星球的渐变填充颜色
	this.color = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius)
	this.color.addColorStop(0, this.startColor)
	this.color.addColorStop(1, this.endColor)
	ctx.fillStyle = this.color
	ctx.fill()
	ctx.restore()
	this.time += 1
  }
}

const sun = new Star(0, 0, 10, 1, '#f00', '#f90')
const mercury = new Star(0, -SPAN, 10, 87.70, '#a69697', '#5c3e40')
const venus = new Star(0, -SPAN * 2, 10, 224.70, '#c4bbac','#1f1315')
const earth = new Star(0, -SPAN * 3, 10, 365.2422, '#78b1e8', '#050c12')
const mars = new Star(0, -SPAN * 4, 10, 686.98, '#cec9b6', '#76422d')
const jupiter = new Star(0, -SPAN * 5, 10, 4332.589, '#cda48e', '#322222')
const satum = new Star(0, -SPAN * 6, 10, 10759.5, '#f7f9e3', '#5c4533')
const uranus = new Star(0, -SPAN * 7, 10, 30799.095, '#f7f9e3', '#19243a')
const neptune = new Star(0, -SPAN * 8, 10, 60152, '#0661b2', '#1e3b73')

function move(){
    
    
	ctx.clearRect(0, 0, 1000, 1000)
	drawTrack()
    sun.draw()
	mercury.draw()
	venus.draw()	
	earth.draw()
	mars.draw()
	jupiter.draw()
	satum.draw()
	uranus.draw()
	neptune.draw()
}

setInterval(move, 10)

猜你喜欢

转载自blog.csdn.net/weixin_43443341/article/details/127054230
今日推荐