【实例】canvas-精灵-享元模式

274 阅读1分钟

实力样式

iao.gif

重点代码

function drawHands(){
  let date = new Date()
      hour = date.getHours()

  ball.width = 20
  ball.height = 20
  drawHand(date.getSeconds(),false)

  hour = hour > 12 ? hour - 12 : hour
  ball.width = 35
  ball.height = 35
  drawHand(date.getMinutes(),false)


  ball.width = 50
  ball.height = 50
  drawHand(hour * 5  + (date.getMinutes() / 60) *5)

  ball.width = 10
  ball.height = 10
  ball.left =  canvas.width / 2 - ball.width/ 2
  ball.top = canvas.height/ 2 - ball.height/2
  ballPainter.paint(ball,ctx)
}

这部分中就是说明了享元模式:使用一个对象来表示多个概念,其减少了需要创建的对象数,从而减少了内存占用量

代码中只创建了一个ball对象,但是通过多次的改变ball.widthball.height来实现不同的针的绘制

实例代码

let canvas = document.getElementById('myCanvas')
let ctx = canvas.getContext('2d')

const CLOCK_RADIUS = canvas.height / 2 - 15, 
      HOUR_HAND_TRUNCATION = 35

let ballPainter = {
  paint: function(sprite, ctx){
    let x = sprite.left + sprite.width / 2
        y = sprite.top + sprite.height / 2
        width = sprite.width
        height = sprite.height
        raduis = sprite.width / 2
    ctx.save()
    ctx.beginPath()
    ctx.arc(x, y, raduis, 0, Math.PI * 2, false)
    ctx.clip()

    ctx.shadowColor = 'rgb(0,0,0)'
    ctx.shadowOffsetX = -4 
    ctx.shadowOffsetY = -4
    ctx.shadowBlur = 8
    
    ctx.fillStyle = 'rgba(218,165,32,0.1)'
    ctx.fill()
    ctx.strokeStyle = 'rgb(100,100,195)'
    ctx.stroke()
    ctx.restore()
  }
}

let ball = new Sprite('ball', ballPainter)

function drawHand(loc, isHour){
  let angle = (Math.PI *2) * (loc / 60) - Math.PI/2 , 
      handRadius = isHour ? CLOCK_RADIUS - HOUR_HAND_TRUNCATION : CLOCK_RADIUS,
      lineEnd = {
        x: canvas.width/ 2 + Math.cos(angle) * (handRadius - ball.width / 2),
        y: canvas.height/2 + Math.sin(angle) * (handRadius - ball.height / 2)
      }

  ctx.beginPath()
  ctx.moveTo(canvas.width/2 , canvas.height/2)
  ctx.lineTo(lineEnd.x, lineEnd.y)
  ctx.stroke()
  ball.left = canvas.width / 2 + Math.cos(angle) * handRadius - ball.width / 2
  ball.top = canvas.height / 2 + Math.sin(angle) * handRadius - ball.height / 2
  ball.paint(ctx)
}

function drawClock(){
  drawClockFace()
  drawHands()
}

function drawHands(){
  let date = new Date()
      hour = date.getHours()

  ball.width = 20
  ball.height = 20
  drawHand(date.getSeconds(),false)

  hour = hour > 12 ? hour - 12 : hour
  ball.width = 35
  ball.height = 35
  drawHand(date.getMinutes(),false)


  ball.width = 50
  ball.height = 50
  drawHand(hour * 5  + (date.getMinutes() / 60) *5)

  ball.width = 10
  ball.height = 10
  ball.left =  canvas.width / 2 - ball.width/ 2
  ball.top = canvas.height/ 2 - ball.height/2
  ballPainter.paint(ball,ctx)
}

function drawClockFace(){
  ctx.beginPath()
  ctx.arc(canvas.width/2, canvas.height/2,CLOCK_RADIUS,0,Math.PI*2,false)
  ctx.save()
  ctx.strokeStyle = 'rgba(0,0,0,0.2)'
  ctx.stroke()
  ctx.restore()
}


function animation(){
  ctx.clearRect(0,0,canvas.width,canvas.height)
  C.drawGrind(ctx,'linegray',10,10, canvas.width, canvas.height)
  drawClock()
  window.requestAnimationFrame(animation)
}

ctx.lineWidth = 2
ctx.strokeStyle = 'rgba(0,0,0,0.2)'
ctx.shadowColor = 'rgba(0,0,0,0.5)'
ctx.shadowOffsetX= 2
ctx.shadowOffsetY= 2
ctx.shadowBlur = 4

window.requestAnimationFrame(animation)
C.drawGrind(ctx,'linegray',10,10, canvas.width, canvas.height)