canvas绘制时遇到画布大小与CSS设置的大小不一致导致图形缩放的问题及其解决方法

1.问题描述

        项目中使用canvas绘制一些线条,于是开始动手写了一些小demo。先在网页上创建了一个,然后通过CSS把它的width和height都设置为500px,然后我开始绘制一条从(0,0)到(250,250)的线,正常情况下应该展示为一条从canvas左上角到中心的斜线。
        但是实际情况却大大出乎我的意料,这条线看起来经过了缩放,而且看起来宽和高的缩放比例不一样的。

<script setup lang="ts">
import { onMounted} from "vue";
onMounted(async () => {
  const canvas = document.querySelector(`canvas`) as HTMLCanvasElement;
  const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
  if (ctx) {
    ctx.strokeStyle = `rgba(95, 189, 255,  1)`;
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(250, 250);
    ctx.stroke();
  }
});
</script>
<template>
  <div>
    <canvas></canvas>
  </div>
</template>
<style scoped>
canvas {
  width: 500px;
  height: 500px;
  border: 1px solid black;
  box-sizing: content-box;
}
</style>

线条被缩放了

2. 问题分析

        分析线条的情况,可以推断出我指定的(250,250)这个位置,与canvas认为的不一致。canvas认为的(250,250)这个位置并不是在网页上500px X 500px 的中心。所以问题出现在canvas的真实大小与它展示的大小不一致。于是我查阅资料,打印了canvas的真实大小:

  console.log(canvas.width);
  console.log(canvas.height);

canvas真实大小
        那现在问题就很明朗了,canvas的CSS像素为500px X 500px,这是它在网页上展示的大小,也称逻辑像素。而canvas它自己有个它认为的大小是300 × 150 ,所以我画(250,250)这个位置,就会超过canvas画布范围。
        作为验证,可以绘制一条从(0,0)到(150,75)再回到(300,0)的线,看看是否到中心再回右上角:

<script setup lang="ts">
import { onMounted} from "vue";
onMounted(async () => {
  const canvas = document.querySelector(`canvas`) as HTMLCanvasElement;
  const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
  if (ctx) {
    ctx.strokeStyle = `rgba(95, 189, 255,  1)`;
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(150, 75);
    ctx.lineTo(300, 0);
    ctx.stroke();
  }
});
</script>
<template>
  <div>
    <canvas></canvas>
  </div>
</template>
<style scoped>
canvas {
  width: 500px;
  height: 500px;
  border: 1px solid black;
  box-sizing: content-box;
}
</style>

        果然是这样:
拐回来的线

3. 解决方法

3.1 设置canvas真实大小(在typescript/javascript代码中设置)

        可以手动把canvas的真实大小设置为和CSS设置的大小500×500一样,这样就一致了。代码很简单:

  const canvas = document.querySelector(`canvas`) as HTMLCanvasElement;
  canvas.width = 500;
  canvas.height = 500;
  const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
  if (ctx) {
    ctx.strokeStyle = `rgba(95, 189, 255,  1)`;
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(250, 250);
    ctx.lineTo(500, 0);
    ctx.stroke();
  }

        这时候再绘制一条从(0,0)到(250,250)的线,就正常了:
正常了

3.2 设置canvas真实大小(在html5代码中内联设置)

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

内联设置
         效果是一样的,两种办法设置的是同一个东西。

console.log(canvas.width);
console.log(canvas.height);

在这里插入图片描述

3.3 在 < canvas >中更正分辨率(官方推荐的方法!!!强烈建议!!!)

        官方文档里推荐了一种更正分辨率的方法,实测这种办法充分考虑了物理像素和逻辑像素的差异,并进行修正,效果更好,更清晰!!!

const canvas = document.querySelector(`canvas`) as HTMLCanvasElement;
// Set display size (css pixels).
const size = 500;
canvas.style.width = size + "px";
canvas.style.height = size + "px";
// Set actual size in memory (scaled to account for extra pixel density).
const scale = window.devicePixelRatio; // Change to 1 on retina screens to see blurry canvas.
canvas.width = Math.floor(size * scale);
canvas.height = Math.floor(size * scale);
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
// Normalize coordinate system to use css pixels.
ctx.scale(scale, scale);
if (ctx) {
  ctx.strokeStyle = `rgba(95, 189, 255,  1)`;
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.lineTo(250, 250);
  ctx.lineTo(500, 0);
  ctx.stroke();
}

推荐做法

  • 20
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸法空如

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值