具有固定线宽的响应式画布

Nat*_*.js 4 html javascript css canvas

我正在用画布绘制折线图。图表具有响应性,但线条必须具有固定宽度。

我用 css 让它响应

    #myCanvas{
        width: 80%;
    }
Run Code Online (Sandbox Code Playgroud)

,所以描边被缩放。

我找到的唯一解决方案是使用画布的宽度属性与其实际宽度之间的比例来获取 lineWidth 的值。为了应用它,我在调整大小时清除并绘制画布。

    <canvas id="myCanvas" width="510" height="210"></canvas>

<script type="text/javascript">
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");   
    function draw(){
        var canvasattrwidth = $('#myCanvas').attr('width');
        var canvasrealwidth = $('#myCanvas').width();
        // n sets the line width
        var n = 4;
        var widthStroke = n * (canvasattrwidth / canvasrealwidth) ;
        ctx.lineWidth = widthStroke;
        ctx.beginPath();
        ctx.moveTo( 0 , 10 );
        ctx.lineTo( 200 , 100 );
        ctx.stroke();
    }
    $(window).on('resize', function(){
        ctx.clearRect(0, 0, c.width, c.height);
        draw();
    });
    draw();
</script>
Run Code Online (Sandbox Code Playgroud)

这是我的第一个画布,我认为有一种更简单的方法可以使 lineWidth 固定(不是每次都在调整大小时清除和绘制),但我找不到它。

有一个类似问题的问题

html5 canvas 阻止线宽缩放, 但使用 scale() 方法,因此我无法使用该解决方案。

Bli*_*n67 5

无法获得画布的真实世界细节尺寸,例如毫米或英寸,因此您必须以像素为单位。

随着画布分辨率的降低,线条的像素宽度也需要降低。线宽的限制属性是一个像素。渲染比像素更窄的线条只会通过降低不透明度来近似更窄线条的外观(这是自动完成的)

您需要根据您期望的最低分辨率定义线宽,当然,并在画布分辨率相对于此选定的理想分辨率发生变化时调整该宽度。

如果您在 x 和 y 方向按不同的量缩放图表,则必须使用ctx.scalectx.setTransform方法。正如您所说的,您不想这样做,我将假设您的缩放比例始终为方形。

所以我们可以选择可接受的最低分辨率。假设画布的宽度或高度为 512 像素,并lineWidth为该分辨率选择以像素为单位。

因此我们可以创建两个常量

const NATIVE_RES = 512; // the minimum resolution we reasonably expect
const LINE_WIDTH = 1;   // pixel width of the line at that resolution
                        // Note I Capitalize constants, This is non standard in Javascript
Run Code Online (Sandbox Code Playgroud)

然后计算实际线宽只是实际canvas.width除以NATIVE_RES然后乘以结果LINE_WIDTH

var actualLineWidth = LINE_WIDTH * (canvas.width / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
Run Code Online (Sandbox Code Playgroud)

您可能希望将该大小限制为最小的画布尺寸。你可以这样做,Math.min或者你可以将它限制在最大的维度上Math.max

对于最小尺寸。

var actualLineWidth = LINE_WIDTH * (Math.min(canvas.width, canvas.height) / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
Run Code Online (Sandbox Code Playgroud)

对于最大尺寸

var actualLineWidth = LINE_WIDTH * (Math.max(canvas.width, canvas.height) / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
Run Code Online (Sandbox Code Playgroud)

您还可以将对角线视为包含 x 和 y 维度中最佳维度的调整因子。

// get the diagonal resolution
var diagonalRes = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
var actualLineWidth = LINE_WIDTH * (diagonalRes / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
Run Code Online (Sandbox Code Playgroud)

最后,当线条小于 1 像素时,您可能希望限制线条的较低范围以阻止奇怪的伪影。

使用对角线设置下限

var diagonalRes = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
var actualLineWidth = Math.max(1, LINE_WIDTH * (diagonalRes / NATIVE_RES));
ctx.lineWidth = actualLineWidth;
Run Code Online (Sandbox Code Playgroud)

如果画布对角线分辨率低于 512,这将创建一个响应线宽不会低于 1 像素。

您使用的方法取决于您。试试看,看看你最喜欢什么。在NATIVE_RES我拿起“512”也是任意的,可以是你想要什么都。您只需要尝试使用这些值和方法来查看您最喜欢哪个。

如果您的缩放方面正在发生变化,那么有一种完全不同的技术可以解决该问题,我将留给另一个问题。

希望这有帮助。