Javascript 如何在画布中缩放图像?

Javascript 如何在画布中缩放图像?,javascript,html,css,canvas,Javascript,Html,Css,Canvas,我试图在画布中使用cover模拟来显示图像。我找到了一些很酷的方法 到目前为止,我的图像会根据屏幕分辨率进行更改,但只有在刷新页面后才会更改 如何在不刷新页面的情况下获取以下内容? 尝试调整窗口的大小 HTML <canvas id="canvas"></canvas> JS var ctx = canvas.getContext('2d'), img = new Image; canvas.setAttribute('width', window.i

我试图在画布中使用
cover
模拟来显示图像。我找到了一些很酷的方法

到目前为止,我的图像会根据屏幕分辨率进行更改,但只有在刷新页面后才会更改

如何在不刷新页面的情况下获取以下内容? 尝试调整窗口的大小

HTML

<canvas id="canvas"></canvas> 

JS

var ctx = canvas.getContext('2d'),
    img = new Image;

canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);

img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/0/0f/2010-02-19_3000x2000_chicago_skyline.jpg';

function draw() {
    drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height);
}

/**
 * By Ken Fyrstenberg
 *
 * drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
 *
 * If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {

    if (arguments.length === 2) {
        x = y = 0;
        w = ctx.canvas.width;
        h = ctx.canvas.height;
    }

    /// default offset is center
    offsetX = offsetX ? offsetX : 0.5;
    offsetY = offsetY ? offsetY : 0.5;

    /// keep bounds [0.0, 1.0]
    if (offsetX < 0) offsetX = 0;
    if (offsetY < 0) offsetY = 0;
    if (offsetX > 1) offsetX = 1;
    if (offsetY > 1) offsetY = 1;

    var iw = img.width,
        ih = img.height,
        r = Math.min(w / iw, h / ih),
        nw = iw * r,   /// new prop. width
        nh = ih * r,   /// new prop. height
        cx, cy, cw, ch, ar = 1;

    /// decide which gap to fill    
    if (nw < w) ar = w / nw;
    if (nh < h) ar = h / nh;
    nw *= ar;
    nh *= ar;

    /// calc source rectangle
    cw = iw / (nw / w);
    ch = ih / (nh / h);

    cx = (iw - cw) * offsetX;
    cy = (ih - ch) * offsetY;

    /// make sure source rectangle is valid
    if (cx < 0) cx = 0;
    if (cy < 0) cy = 0;
    if (cw > iw) cw = iw;
    if (ch > ih) ch = ih;

    /// fill image in dest. rectangle
    ctx.drawImage(img, cx, cy, cw, ch,  x, y, w, h);
}
var ctx=canvas.getContext('2d'),
img=新图像;
canvas.setAttribute('width',window.innerWidth);
canvas.setAttribute('height',window.innerHeight);
img.onload=牵引;
img.src=https://upload.wikimedia.org/wikipedia/commons/0/0f/2010-02-19_3000x2000_chicago_skyline.jpg';
函数绘图(){
drawImageProp(ctx,this,0,0,canvas.width,canvas.height);
}
/**
*肯·菲尔斯滕伯格
*
*drawImageProp(上下文、图像[、x、y、宽度、高度[、偏移量x、偏移量]])
*
*若图像和上下文是唯一的参数,那个么矩形将等于画布
*/
函数drawImageProp(ctx、img、x、y、w、h、offsetX、offsetY){
if(arguments.length==2){
x=y=0;
w=ctx.canvas.width;
h=ctx.canvas.height;
}
///默认偏移量为“中心”
offsetX=offsetX?offsetX:0.5;
偏移量=偏移量?偏移量:0.5;
///保持界限[0.0,1.0]
如果(offsetX<0)offsetX=0;
如果(偏移量<0)偏移量=0;
如果(offsetX>1)offsetX=1;
如果(offsetY>1)offsetY=1;
var iw=img.width,
ih=img.高度,
r=数学最小值(w/iw,h/ih),
nw=iw*r,///新道具宽度
nh=ih*r,///新道具高度
cx,cy,cw,ch,ar=1;
///决定填补哪个空白
如果(nwiw)cw=iw;
如果(ch>ih)ch=ih;
///在目标矩形中填充图像
ctx.drawImage(img、cx、cy、cw、ch、x、y、w、h);
}

在以下位置添加对
绘图的调用:

这应该能奏效

而不是:

drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height);
通过
draw
功能中的
img

drawImageProp(ctx, img, 0, 0, canvas.width, canvas.height);
然后,将宽度/高度设置移动到
draw
功能中,导致:

function draw() {
    canvas.setAttribute('width', window.innerWidth);
    canvas.setAttribute('height', window.innerHeight);
    drawImageProp(ctx, img, 0, 0, canvas.width, canvas.height);
}
您可能还需要稍微消除重新绘制的影响:

var timeOut;
window.onresize = function(){
    if(timeOut)
        clearTimeout(timeOut);
    timeOut = setTimeout(draw, 10);
}
这可以防止在调整窗口大小时每秒调用几次
draw
函数

这是,从您的代码笔中分叉。

这很有效

var ctx=canvas.getContext('2d'),
img=新图像;
canvas.setAttribute('width',window.innerWidth);
canvas.setAttribute('height',window.innerHeight);
img.onload=牵引;
img.src=https://upload.wikimedia.org/wikipedia/commons/0/0f/2010-02-19_3000x2000_chicago_skyline.jpg';
函数绘图(){
drawImageProp(ctx、img、0、0、canvas.width、canvas.height);
}
window.onresize=调整大小;
函数resize(){
canvas.setAttribute('width',window.innerWidth);
canvas.setAttribute('height',window.innerHeight);
画()
}
/**
*肯·菲尔斯滕伯格
*
*drawImageProp(上下文、图像[、x、y、宽度、高度[、偏移量x、偏移量]])
*
*若图像和上下文是唯一的参数,那个么矩形将等于画布
*/
函数drawImageProp(ctx、img、x、y、w、h、offsetX、offsetY){
if(arguments.length==2){
x=y=0;
w=ctx.canvas.width;
h=ctx.canvas.height;
}
///默认偏移量为“中心”
offsetX=offsetX?offsetX:0.5;
偏移量=偏移量?偏移量:0.5;
///保持界限[0.0,1.0]
如果(offsetX<0)offsetX=0;
如果(偏移量<0)偏移量=0;
如果(offsetX>1)offsetX=1;
如果(offsetY>1)offsetY=1;
var iw=img.width,
ih=img.高度,
r=数学最小值(w/iw,h/ih),
nw=iw*r,///新道具宽度
nh=ih*r,///新道具高度
cx,cy,cw,ch,ar=1;
///决定填补哪个空白
如果(nwiw)cw=iw;
如果(ch>ih)ch=ih;
///在目标矩形中填充图像
ctx.drawImage(img、cx、cy、cw、ch、x、y、w、h);
}

应该注意,画布上的缩放不起作用。画在画布上的东西不能像画一样被操纵。图像应该在调整大小的画布上重画。@Grimbode:我想我现在已经画好了。最好的做法是先清理画布,然后重画,还是如果以前的画不再可见,重画就足够了?这对性能有什么影响?在画布上设置宽度/高度已经可以清除画布。设置这些属性是必须做的事情。在画布上重画一次图像相对来说是无关紧要的。我认为您确实需要保持加载状态,因为您可以在图像可能仍未加载时调整窗口大小。这将在缩放窗口时连续调整画布大小(从而重新绘制)。这是非常低效的。@cerbru这个选项速度要快得多。如果速度有问题,你可以将我回答的延迟从
500
降低到,比如说,
10
,甚至更低。然后画布将立即(表面上)重新绘制,而不会在调整窗口大小的过程中实际重新绘制70次。
var timeOut;
window.onresize = function(){
    if(timeOut)
        clearTimeout(timeOut);
    timeOut = setTimeout(draw, 10);
}