Every time you want to systematically learn canvas, the normal process is

  1. See something cool
  2. Open MDN with gusto
  3. Turn it off after five minutes of aimless browsing

So I want to change tactics this time, starting from small needs, from the countryside to encircle the city!

The signature

This should be a very common requirement

Train of thought

The idea is very direct, draw directly, will use the following API 🙂

  • beginPathCreate a new path
  • lineWidthSet the segment thickness property (that is, the width of the segment)
  • strokeStyleProperty that describes the color or style of the paintbrush. The default is black
  • moveTo(x, y)Method of moving the starting point of a new subpath to (x, y) coordinates (not actually drawn)
  • lineTo(x, y)Use straight lines to connect ends of subpaths to x, y coordinates (without actually drawing)
  • closePathDraw a line from the current point to the starting point
  • strokeActually draw the path defined by the moveTo() and lineTo() methods, with the default color black

code

const canvas=document.getElementById("canvas")
const ctx=canvas.getContext("2d")
canvas.width = 800
canvas.height = 800

/ / style
ctx.lineWidth = 2;
ctx.strokeStyle = "#fff";

// get the moving coordinates
const getRealCoordinate = (event) = > {
  const canvasOffsetLeft = canvas.offsetLeft
  const canvasOffsetTop = canvas.offsetTop
  return {
    x: event.clientX - canvasOffsetLeft,
    y: event.clientY - canvasOffsetTop
  }
}

const handleMouseMove = (event) = >{
  const { x, y } = getRealCoordinate(event)
  ctx.lineTo(x, y);
  ctx.stroke();
}

const handleMouseDown = (event) = > {
  ctx.beginPath();
  const { x, y } = getRealCoordinate(event)
  ctx.moveTo(x, y);

  canvas.addEventListener('mousemove', handleMouseMove)
}

canvas.addEventListener('mousedown', handleMouseDown)

 canvas.addEventListener('mouseup'.(e) = >{
  canvas.removeEventListener('mousemove', handleMouseMove)
})
Copy the code

Scratch music

Train of thought

  1. Overlay canvas absolute position on the winning base image
  2. To listen for the sliding action, useclearRectClear a small piece of canvas in the sliding section

code

view

  <style>
  .box{
    position: relative;
    width: 300px;
    height: 300px;
  }
   /* * */
  .prize{
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background: coral;
    font: 50px serif
  }
  /* canvas */
  #prize-mask{
   position: absolute;
   top: 0;
   left: 0;
   cursor: pointer;
   z-index: 10;
  }
</style>
<div class="box"">
  <div class="prize">10 million</div>
  <canvas id="prize-mask" />
</div>
Copy the code

js

const canvas = document.querySelector('#prize-mask')
const ctx = canvas.getContext('2d')

// Get the outer width and dynamically set the width
const { clientWidth: wrapWidth, clientHeight: wrapHeight} = document.querySelector('.box')
canvas.width = wrapWidth
canvas.height = wrapHeight

const { clientWidth: canvasWidth, clientHeight: canvasHeight } = canvas

const text = 'Good luck'

    // Set some canvas properties
ctx.fillStyle='black'
ctx.fillRect(0.0,canvasWidth,canvasHeight)
ctx.font='50px serif'
ctx.strokeStyle='red'
ctx.strokeText(text, ( canvasWidth - ctx.measureText( text ).width ) / 2, canvasHeight / 2 )   // The text is centered
ctx.save()


const handleMouseMove = (event) = >{
ctx.clearRect(event.offsetX,event.offsetY,20.20);
}

const handleMouseDown = () = > {
  canvas.addEventListener('mousemove', handleMouseMove)
}

canvas.addEventListener('mousedown', handleMouseDown)

 canvas.addEventListener('mouseup'.(e) = >{
  canvas.removeEventListener('mousemove', handleMouseMove)
})
Copy the code

The effect

Pay attention to the point

Setting the width and height of the canvas, not in the class, will cause a lot of tension/confusion

Let me draw a grid

code

const canvas=document.getElementById("canvas")
const context=canvas.getContext("2d")
const canvasWidth=800
const canvasHeight=800
const cap=50 / / interval
const colNum=Math.ceil(canvasWidth/cap)-1
const rowNum=Math.ceil(canvasHeight/cap)-1
let Grids=[]
const lineWidth=2
canvas.width=800
canvas.height=800

// Create a grid
function initGrid(cap,width,height,lineWidth){
  const colNum=Math.ceil(width/cap)-1
  const rowNum=Math.ceil(height/cap)-1
  for(let i=1; i<=colNum; i++){ Grids.push([[cap*i-1.0,lineWidth,colNum*cap],[i*cap,cap*i-1,colNum*cap+5."top"."center"]])}for(let i=1; i<=rowNum; i++){ Grids.push([[0,cap*i-1,rowNum*cap,lineWidth],[i*cap,rowNum*cap+5,cap*i-1."middle"."left"]])
  }
}

initGrid(cap,canvasWidth,canvasHeight,lineWidth);

function createGrid(){
  context.fillStyle = 'green';
  context.font="24px Arial"
  Grids.forEach((grid) = >{
    context.textAlign=grid[1] [4]
     context.textBaseline=grid[1] [3]
     context.fillRect(grid[0] [0],grid[0] [1], grid[0] [2], grid[0] [3])
     context.fillText(grid[1] [0],grid[1] [1], grid[1] [2]);   
  })
}
createGrid()
Copy the code

Some API notes

BeginPath and closePath

BeginPath – Starts a new path, or resets a new path

e.g

var ctx = document. getElementById ( 'canvas' ) . getContext ( '2d'); ctx. beginPath ( ) ; ctx. moveTo (100 , 20); ctx. lineTo (200 , 20); ctx. strokeStyle ='white' ; 
ctx. stroke ( ) ; 
ctx.beginPath() // important
ctx.moveTo(100.40)
ctx. lineTo ( 200 , 40 ) 
ctx. strokeStyle = 'red' ; 
ctx. stroke ( ) ;
Copy the code

The code above will draw a white line and a red line, and if there is no second beginPath, it will end up drawing two red lines

ClosePath – Has nothing to do with beginPath, this API just closes a path by drawing a line from the current point to the start of the path