我们将一些文字放在带有
的HTML5<canvas>
上
var canvas = document.getElementById('myCanvas'),
ctx = canvas.getContext('2d'),
ctx.textBaseline = 'top';
ctx.textAlign = 'left';
ctx.font = '14px sans-serif';
ctx.fillText('Bonjour', 10, 10);
在文本上缩放画布时,可以看到像素化。
有没有办法在画布上放大而不会在文字上出现像素化?
答案 0 :(得分:1)
当您在画布上fillText
时,它将停止为字母并开始成为字母形状的像素集合。当您放大它时,像素会变大。这就是画布的工作方式。
如果希望文本缩放为基于矢量的字体而不是像素,请不要在画布上绘制它们。您可以创建<span>
HTML元素,并使用CSS定位将它们放在画布顶部。这样,渲染引擎将在放大时以更高的分辨率渲染字体,并且它们将保持清晰。但是你在画布上绘制的任何内容都会相应缩放。
或者,您可以覆盖浏览器缩放功能并创建自己的缩放算法,但这将是一些工作。
当用户放大或缩小窗口时,会触发window.onresize
事件处理程序。您可以使用此触发器相应地调整画布css样式的宽度和高度(而不是画布的属性。这是内部渲染分辨率。更改样式的宽度和高度属性,它是缩放到的分辨率的分辨率。网站)。
现在,您已经有效地禁用了用户Web浏览器调整画布的大小,并且还有一个可以对缩放输入事件做出反应的位置。您可以使用它来调整画布的context.scale
以更改您绘制的所有内容的大小,包括字体。
以下是一个例子:
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
"use strict"
var canvas;
var context;
function redraw() {
// clears the canvas and draws a text label
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.font = "60pt sans-serif";
context.fillText("Hello World!", 100, 100);
}
function adjustSize() {
var width = window.innerWidth;
var height = window.innerHeight;
// resize the canvas to fill the whole screen
var style = canvas.style;
style.width = width + "px";
style.height = height + "px";
// backup the old current scaling factor
context.save();
// change the scaling according to the new zoom factor
context.scale(1000 / width, 1000 / height);
// redraw the canvas
redraw();
// restore the original scaling (important because multiple calls to scale are relative to the current scale factor)
context.restore();
}
window.onload = function() {
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
adjustSize();
}
window.onresize = adjustSize;
</script>
</head>
<body>
<canvas id ="myCanvas" width = 1000 height = 1000 ></canvas>
</body>
</html>
答案 1 :(得分:1)
如果您只需缩放文字,只需缩放字体即可。
然而,关于这一点的几点注意事项:字体或字体不仅仅是直接扩展意味着你将无法顺利进展。这是因为字体通常针对特定尺寸进行了优化,因此两者之间的尺寸可以说是前一尺寸和下一尺寸的结果。这可以使字体看起来像是在放大时移动一点并且是正常的和预期的。
此处的方法使用简单的大小比例。如果你需要一个绝对平滑的比例用于动画目的,你将不得不使用一种非常不同的技术。
简单的方法是:
ctx.font = (fontSize * scale).toFixed(0) + 'px sans-serif';
出于动画目的,您需要执行以下操作:
In this demo 你可以看到,在较小的尺寸下,像素会变得有点“块状”,但除此之外比纯文本方法更平滑。
这是因为浏览器使用双线性插值而不是双立方与画布(将来可能会或可能不会改变),因此当差异变大时,它无法正确插值(请参阅下面的解决方案)这个问题)。
相反的情况发生在大尺寸,因为插值会使文字变得模糊。
这是我们必须切换到更小(或更大)的缓存版本的地方,然后我们会在再次切换之前在一定范围内进行缩放。
该演示简化为仅显示单个缓存版本。你可以看到中途工作正常。原则将是一个完整的解决方案(尺寸只是示例):
(缩放时,更新Here is a demo 切换后的图片。)
-- Cached image (100px)
-- Draw cached image above scaled based on zoom between 51-100 pixels
-- Cached image (50px) generated from 100px version / 2
-- Draw cached image above scaled based on zoom between 26-50 pixels
-- Cached image (25px) generated from 50px version / 2
-- Draw cached image above scaled based on zoom between 1-25 pixels
然后使用“甜蜜点”(通过实验稍微找到)在缓存版本之间切换,然后再将它们绘制到屏幕上。
var ctx = canvas.getContext('2d'),
scale = 1, /// initial scale
initialFactor = 6, /// fixed reduction scale of cached image
sweetSpot = 1, /// threshold to switch the cached images
/// create two off-screen canvases
ocanvas = document.createElement('canvas'),
octx = ocanvas.getContext('2d'),
ocanvas2 = document.createElement('canvas'),
octx2 = ocanvas2.getContext('2d');
ocanvas.width = 800;
ocanvas.height = 150;
ocanvas2.width = 400; /// 50% here, but maybe 75% in your case
ocanvas2.height = 75; /// experiment to find ideal size..
/// draw a big version of text to first off-screen canvas
octx.textBaseline = 'top';
octx.font = '140px sans-serif';
octx.fillText('Cached text on canvas', 10, 10);
/// draw a reduced version of that to second (50%)
octx2.drawImage(ocanvas, 0, 0, 400, 75);
现在我们只需要检查最佳位置值,找出何时在这些版本之间切换:
function draw() {
/// calc dimensions
var w = ocanvas.width / initialFactor * scale,
h = ocanvas.height / initialFactor * scale;
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (scale >= sweetSpot) {
ctx.drawImage(ocanvas, 10, 10, w, h); /// use cached image 1
} else {
ctx.drawImage(ocanvas2, 10, 10, w, h); /// use cached image 2
}
}
那么为什么不用字体绘制第二个缓存图像呢?你可以这样做,但是你回到了针对某些尺寸优化的字体的问题,并且在缩放时会产生一个小的跳跃。如果您可以使用它,那么使用它,因为它将提供更好的质量(特别是在小尺寸)。如果你需要平滑的动画,你必须减少一个更大的缓存版本,以保持100%的比例。
您可以看到this answer如何在没有插值问题的情况下调整大图像的大小。
希望这有帮助。