[英]How and why is canvas width/height messing with my image drawing?
我正在尝试编写一个函数,该函数接受x,y坐标和旋转,并将围绕图像中心点旋转的图像插入画布。 这段代码可以正常工作:
let img = new Image(), canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), step = 0, drawImage = (ctx, img, x, y, degrees, w = 150, h = 150) => { ctx.save(); ctx.translate(x+w/4, y+h/4); ctx.rotate(degrees*Math.PI/180.0); ctx.translate(-xw/4, -yh/4); ctx.drawImage(img, x, y, w, h); ctx.restore(); }, animate = () => { ctx.globalCompositeOperation = 'destination-over'; // clear canvas ctx.clearRect(0, 0, window.innerWidth, window.innerHeight); drawImage(ctx, img, 0, 0, step) step++; window.requestAnimationFrame(animate); } img.src = "http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg"; animate();
* { margin:0; padding:0; } /* to remove the top and left whitespace */ html, body { width:100%; height:100%; } /* just to be sure these are full screen*/ canvas { display:block;} /* To remove the scrollbars */
<canvas id="canvas" width="300" height="300">
但是当我尝试调整画布大小时
canvas.width =window.innerWidth;
canvas.height = window.innerHeight;
这会使图像变形并且还会改变旋转点,在更大的窗口上效果更加清晰。 我怎样才能拥有一个充满屏幕的画布,并像使用HTML属性设置尺寸一样对待它呢?
let img = new Image(), canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), step = 0, drawImage = (ctx, img, x, y, degrees, w = 300, h = 300) => { ctx.save(); ctx.translate(x+w/4, y+h/4); ctx.rotate(degrees*Math.PI/180.0); ctx.translate(-xw/4, -yh/4); ctx.drawImage(img, x, y, w, h); ctx.restore(); }, animate = () => { ctx.globalCompositeOperation = 'destination-over'; // clear canvas ctx.clearRect(0, 0, window.innerWidth, window.innerHeight); drawImage(ctx, img, 0, 0, step) step++; window.requestAnimationFrame(animate); } img.src = "http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg"; canvas.width =window.innerWidth; canvas.height = window.innerHeight; animate();
* { margin:0; padding:0; } /* to remove the top and left whitespace */ html, body { width:100%; height:100%; } /* just to be sure these are full screen*/ canvas { display:block;} /* To remove the scrollbars */
<canvas id="canvas" width="300" height="300">
这是Chrome的“错误”,与您要求绘制的错误svg图像有关。
您绘制的svg没有绝对的width
或height
属性,也没有viewBox
。
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect width="150" height="150" fill="rgb(0, 255, 0)" stroke-width="1" stroke="rgb(0, 0, 0)"/>
</svg>
这意味着它没有内部尺寸,也没有任何内部比率。 在HTML上下文中,浏览器仍可以通过应用内联替换元素中描述的规则来设置默认大小。
通过遵循这些规则,将svg保存在相对大小的容器中的<img>
的计算尺寸为300 x 150px ( width => 300px
, height => 2:1 * width => 150px
)。 但是,其本征大小为0
,Firefox将通过naturalXXX
属性报告该大小,而Chrome会将其设置为300
和150
。
onload = e => { const img = document.querySelector('img'); console.log( 'computed', img.width, // 300 img.height // 150 ); console.log( 'intrinsic', img.naturalWidth, // 0 in FF, 300 in Chrome img.naturalHeight // 0 in FF, 150 in Chrome ); }
img { border: 1px solid blue}
<img src="http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg">
现在,当您在画布上绘制此图像时,没有这样的CSS规则来指示应如何计算此计算出的大小,并且UA并不同意在画布上绘制此图像时会发生什么。
Firefox将根本无法绘制它(记住,他们成立naturalXXX
至0
。Chrome将使用一些魔法试探法来绘制它认为它应该得出的最好的。这就是我所说的错误。
如果在drawImage
中使用的HTMLImageElement没有srcset
(即,其密度为1
),则drawImage(img, x, y)
产生与drawImage(img, x, y, img.naturalWidth, img.naturalHeight)
相同的结果。
但是,鉴于它们用于这些图像的魔力没有内在的大小,因此不会发生这种情况。
因此,您会看到它在Chrome中变形,因为您要求将其绘制为300 x 300矩形。
const img = new Image(), canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), draw = async () => { const w = img.naturalWidth, h = img.naturalHeight; console.log('reported img size', w, h); ctx.fillRect(0, 0, w, h); await wait(2000); console.log('drawImage with reported size'); ctx.drawImage(img, 0, 0, w, h); await wait(2000); console.log('default drawImage'); ctx.drawImage(img, 0, 0); }; img.src = "http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg"; canvas.width = window.innerWidth; canvas.height = window.innerHeight; img.onload = draw; function wait(ms) { return new Promise(res => setTimeout(res, ms)); }
<canvas id="canvas" width="300" height="300">
因此,您可以尝试通过drawImage(img, x, y, w, h)
来测量所需的比率,该比率与仅使用3个参数时相同,但最好的办法是使用正确的svg,并使用绝对宽度和高度设置,这将使其适用于所有浏览器:
let img = new Image(), canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), step = 0, drawImage = (ctx, img, x, y, degrees, w = 300, h = 300) => { ctx.save(); ctx.translate(x + w / 4, y + h / 4); ctx.rotate(degrees * Math.PI / 180.0); ctx.translate(-x - w / 4, -y - h / 4); ctx.drawImage(img, x, y, w, h); ctx.restore(); }, animate = () => { ctx.globalCompositeOperation = 'destination-over'; // clear canvas ctx.clearRect(0, 0, window.innerWidth, window.innerHeight); drawImage(ctx, img, 0, 0, step) step++; window.requestAnimationFrame(animate); } canvas.width = window.innerWidth; canvas.height = window.innerHeight; img.onload = animate; fetch("https://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg") .then(resp => resp.text()) .then(markup => { const mime = 'image/svg+xml'; const doc = new DOMParser().parseFromString(markup, mime); doc.documentElement.setAttribute('width', 150); doc.documentElement.setAttribute('height', 150); img.src = URL.createObjectURL( new Blob( [new XMLSerializer().serializeToString(doc)], { type: mime } ) ); }) .catch(console.error);
* { margin:0; padding:0; } /* to remove the top and left whitespace */ html, body { width:100%; height:100%; } /* just to be sure these are full screen*/ canvas { display:block;} /* To remove the scrollbars */
<canvas id="canvas" width="300" height="300">
尝试改变
canvas.width =window.innerWidth;
canvas.height = window.innerHeight;
同
canvas.style.width = "100%";
canvas.style.height = "100%";
let img = new Image(), canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), step = 0, drawImage = (ctx, img, x, y, degrees, w = 300, h = 300) => { ctx.save(); ctx.translate(x+w/4, y+h/4); ctx.rotate(degrees*Math.PI/180.0); ctx.translate(-xw/4, -yh/4); ctx.drawImage(img, x, y, w, h); ctx.restore(); }, animate = () => { ctx.globalCompositeOperation = 'destination-over'; // clear canvas ctx.clearRect(0, 0, window.innerWidth, window.innerHeight); drawImage(ctx, img, 0, 0, step) step++; window.requestAnimationFrame(animate); } img.src = "http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg"; canvas.style.width = "100%"; canvas.style.height = "100%"; animate();
* { margin:0; padding:0; } /* to remove the top and left whitespace */ html, body { width:100%; height:100%; } /* just to be sure these are full screen*/ canvas { display:block;} /* To remove the scrollbars */
<canvas id="canvas">
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.