canvas图片旋转

被水印旋转和签名旋转折磨了几天,记录一下免得忘了

首先是创建canvas对象

<template>
  <div class="canvas-container">
    <canvas ref="canvasRef" id="canvas"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'


const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>()

const initCanvas = () => {
  if (canvasRef.value) {
    canvasRef.value.width = 1000
    canvasRef.value.height = 500
    ctx.value = canvasRef.value.getContext('2d')
  }
  
}
onMounted(() => {
  initCanvas()
})
</script>
<style lang="scss" scoped>
  #canvas {
    width: 1000px;
    height: 500px;
  }
</style>

canvas存在默认宽高,注意是canvas的实例宽高,默认300*150,不是style样式宽高,

这里一定要注意,canvas的style的宽高,和canvas实例的宽高需要相同,否则创建出来的canvas内容会按比例转换,比如

<script setup lang="ts">
import { onMounted, ref } from 'vue'


const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>()

const initCanvas = () => {
  if (canvasRef.value) {
    canvasRef.value.width = 1000
    canvasRef.value.height = 500

    ctx.value = canvasRef.value.getContext('2d')
  }
  if (ctx.value) {
    let aspectRatio = 1
    if (canvasRef.value) {
      aspectRatio = canvasRef.value.height / canvasRef.value.width
    }
    ctx.value.translate(100, 100)
    ctx.value.fillStyle = '#953265'
    ctx.value.fillRect(0, 0, 50, 50)
  }
}
onMounted(() => {
  initCanvas()
})
</script>

<template>
  <div class="canvas-container">
    <canvas ref="canvasRef" id="canvas"></canvas>
  </div>
</template>

<style lang="scss" scoped>
  #canvas {
    width: 500px;
    height: 500px;
  }
</style>

按照代码来说,希望canvas移动到(100,100)的位置,并且创建一个50*50的方块,实际上创建的结果是这样的

方块的位置和大小都被等比例压缩了

接下来重新开始,创建canvas,设置宽高, 移动canvas画布位置到(100,100),画一张图片,注意canvas的坐标是以左上角为中心点,向右下展开,水平方向为x轴,竖直方向为y轴

使用drawImage方法画图时注意,图片如果不指定宽高,会直接按图片原始宽高画图,如果希望等比例缩放图片,可以在图片加载后算好宽高比,再指定图片宽高

<script setup lang="ts">
import { onMounted, ref } from 'vue'

const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>()
const canvasWidth = 1000;
const canvasHeight = 500;

const initCanvas = () => {
  if (canvasRef.value) {
    canvasRef.value.width = canvasWidth
    canvasRef.value.height = canvasHeight

    ctx.value = canvasRef.value.getContext('2d')
  }
  if (ctx.value) {
    ctx.value.translate(100, 100)
    const img = document.createElement('img')
    img.src = '/car.png'
    img.onload = (e) => {
      console.log(img.width)
      console.log(img.height)
      ctx.value?.drawImage(img, 0, 0, 128, 80);
      // ctx.value?.rotate(45*Math.PI/180)
      // ctx.value?.drawImage(img, 0, 0, 128, 80);
    }
  }
}
onMounted(() => {
  initCanvas()
})
</script>

<template>
  <div class="canvas-container">
    <canvas ref="canvasRef" id="canvas" :style="{
      width: `${canvasWidth}px`,
      height: `${canvasHeight}px`
    }"></canvas>
  </div>
</template>

<style lang="scss" scoped>
.canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  border: 1px solid;
}
</style>

结果如下

再把画布旋转45度,画图,结果如下 

<script setup lang="ts">
import { onMounted, ref } from 'vue'

const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>()
const canvasWidth = 1000;
const canvasHeight = 500;

const initCanvas = () => {
  if (canvasRef.value) {
    canvasRef.value.width = canvasWidth
    canvasRef.value.height = canvasHeight

    ctx.value = canvasRef.value.getContext('2d')
  }
  if (ctx.value) {
    ctx.value.translate(100, 100)
    const img = document.createElement('img')
    img.src = '/car.png'
    img.onload = (e) => {
      console.log(img.width)
      console.log(img.height)
      ctx.value?.drawImage(img, 0, 0, 128, 80);
      ctx.value?.rotate(45*Math.PI/180)
      ctx.value?.drawImage(img, 0, 0, 128, 80);
    }
  }
}
onMounted(() => {
  initCanvas()
})
</script>

<template>
  <div class="canvas-container">
    <canvas ref="canvasRef" id="canvas" :style="{
      width: `${canvasWidth}px`,
      height: `${canvasHeight}px`
    }"></canvas>
  </div>
</template>

<style lang="scss" scoped>
.canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  border: 1px solid;
}
</style>

可以看到,canvas的旋转是围绕左上角的

那么如何将图片围绕中心旋转呢,基本思路大概就是利用三角函数计算旋转之后向中心点移动的参数(PS:三角函数的知识早就忘记了,又捡起来看了一遍,都是泪)

<script setup lang="ts">
import { onMounted, ref } from 'vue'

const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>()
const canvasWidth = 1000
const canvasHeight = 500
const rectWidth = 150
const rectHeight = 60
const deg = 60
const getRotateParams = (deg: number, width: number, height: number) => {
  const x =  (width/2)*Math.cos(Math.PI*deg/180) + (height/2)*Math.sin(Math.PI*deg/180) - width/2
  const y =
    (Math.cos((Math.PI * deg) / 180) * height) / 2 -
    (Math.sin((Math.PI * deg) / 180) * width) / 2 -
    height / 2
  return {
    x,
    y
  }
}


const initCanvas = () => {
  if (canvasRef.value) {
    canvasRef.value.width = canvasWidth
    canvasRef.value.height = canvasHeight

    ctx.value = canvasRef.value.getContext('2d')
  }
  if (ctx.value) {
    const img = document.createElement('img')
    img.src = '/car.png'
    img.onload = () => {
      const imgAspectRatio = img.height / img.width
      const imgWidth = 200
      const imgHeight = imgWidth * imgAspectRatio
      ctx.value?.drawImage(
        img,
        (canvasWidth - imgWidth) / 2,
        (canvasHeight - imgHeight) / 2,
        imgWidth,
        imgHeight
      )
      ctx.value?.rotate((deg * Math.PI) / 180)
      const { x, y } = getRotateParams(deg,canvasWidth,canvasHeight)
      ctx.value?.translate(x, y)
      ctx.value?.drawImage(
        img,
        (canvasWidth - imgWidth) / 2,
        (canvasHeight - imgHeight) / 2,
        imgWidth,
        imgHeight
      )
    }
  }
}
onMounted(() => {
  initCanvas()
})
</script>

<template>
  <div class="canvas-container">
    <canvas
      ref="canvasRef"
      id="canvas"
      :style="{
        width: `${canvasWidth}px`,
        height: `${canvasHeight}px`
      }"
    ></canvas>
  </div>
</template>

<style lang="scss" scoped>
.canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  border: 1px solid;
}
</style>

这样就成功实现了canvas绕中心点旋转 

实际上以此为延伸,可以实现计算canvas上绕任意点旋转,而不止是中心点

另外附上平移旋转图,重温一下三角函数知识

<script setup lang="ts">
import { onMounted, ref } from 'vue'

const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>()
const canvasWidth = 1000
const canvasHeight = 500
const rectWidth = 150
const rectHeight = 60
const deg = 60
const getRotateParams = (deg: number, width: number, height: number) => {
  const x =
    (width / 2) * Math.cos((Math.PI * deg) / 180) +
    (height / 2) * Math.sin((Math.PI * deg) / 180) -
    width / 2
  const y =
    (Math.cos((Math.PI * deg) / 180) * height) / 2 -
    (Math.sin((Math.PI * deg) / 180) * width) / 2 -
    height / 2
  return {
    x,
    y
  }
}
const initCanvas = () => {
  if (canvasRef.value) {
    canvasRef.value.width = canvasWidth
    canvasRef.value.height = canvasHeight

    ctx.value = canvasRef.value.getContext('2d')
  }
  if (ctx.value) {
    ctx.value?.translate(200, 200)
    ctx.value?.rect(0, 0, rectWidth, rectHeight)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(-200, rectHeight / 2)
    ctx.value?.lineTo(canvasWidth + 200, rectHeight / 2)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(rectWidth / 2, -200)
    ctx.value?.lineTo(rectWidth / 2, canvasHeight - 200)
    ctx.value?.stroke()
    ctx.value?.rotate((deg * Math.PI) / 180)
    ctx.value?.rect(0, 0, rectWidth, rectHeight)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(-200, rectHeight / 2)
    ctx.value?.lineTo(canvasWidth + 200, rectHeight / 2)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(rectWidth / 2, -200)
    ctx.value?.lineTo(rectWidth / 2, canvasHeight - 200)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(0, -200)
    ctx.value?.lineTo(0, canvasHeight - 200)
    ctx.value?.stroke()

    const { x, y } = getRotateParams(deg, rectWidth, rectHeight)
    ctx.value?.translate(x, y)
    ctx.value?.rect(0, 0, rectWidth, rectHeight)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(rectWidth / 2, -200)
    ctx.value?.lineTo(rectWidth / 2, canvasHeight - 200)
    ctx.value?.stroke()
    ctx.value?.beginPath()
    ctx.value?.moveTo(-200, rectHeight / 2)
    ctx.value?.lineTo(canvasWidth + 200, rectHeight / 2)
    ctx.value?.stroke();
    
    const img = document.createElement('img')
    img.src = '/car.png'
    img.onload = () => {
      // const imgAspectRatio = img.height / img.width
      // const imgWidth = 200
      // const imgHeight = imgWidth * imgAspectRatio
      // ctx.value?.drawImage(
      //   img,
      //   (canvasWidth - imgWidth) / 2,
      //   (canvasHeight - imgHeight) / 2,
      //   imgWidth,
      //   imgHeight
      // )
      // ctx.value?.rotate((deg * Math.PI) / 180)
      // const { x, y } = getRotateParams(deg, canvasWidth, canvasHeight)
      // ctx.value?.translate(x, y)
      // ctx.value?.drawImage(
      //   img,
      //   (canvasWidth - imgWidth) / 2,
      //   (canvasHeight - imgHeight) / 2,
      //   imgWidth,
      //   imgHeight
      // )
    }
  }
}
onMounted(() => {
  initCanvas()
})
</script>

<template>
  <div class="canvas-container">
    <canvas
      ref="canvasRef"
      id="canvas"
      :style="{
        width: `${canvasWidth}px`,
        height: `${canvasHeight}px`
      }"
    ></canvas>
  </div>
</template>

<style lang="scss" scoped>
.canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  border: 1px solid;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值