被水印旋转和签名旋转折磨了几天,记录一下免得忘了
首先是创建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>