ความกว้าง/ความสูงของผ้าใบจึงรบกวนการวาดภาพของฉันอย่างไรและเพราะเหตุใด

ฉันกำลังพยายามเขียนฟังก์ชันที่ใช้พิกัด 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(-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);
	}


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(-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);
	}


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">


person Himmators    schedule 04.09.2019    source แหล่งที่มา


คำตอบ (2)


นั่นเป็น "ข้อบกพร่อง" ของ 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 เบราว์เซอร์ยังคงสามารถกำหนดขนาดเริ่มต้นได้ โดยใช้กฎที่อธิบายไว้ใน องค์ประกอบแบบอินไลน์ที่ถูกแทนที่

เมื่อปฏิบัติตามกฎเหล่านี้ <img> การเก็บ Svg ของคุณในคอนเทนเนอร์ที่มีขนาดค่อนข้างดีจะมีขนาดที่คำนวณได้เป็น 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 จะใช้วิทยาการเวทย์มนตร์เพื่อวาดมันให้ดีที่สุดเท่าที่คิดว่าควรวาด และนั่นคือสิ่งที่ผมเรียกว่าจุดบกพร่อง
หาก HTMLImageElement ใช้ใน drawImage ไม่มี 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">

person Kaiido    schedule 05.09.2019
comment
คุณอาจพิจารณาดูที่นี่ ดูเหมือนว่าจะอยู่ในซอยของคุณและคำถามก็ได้รับการดูจำนวนมากแม้จะไม่ได้ใช้งานมาระยะหนึ่งแล้ว ดังนั้นผู้คนคงจะชื่นชอบคำตอบที่ดี ฉันพยายามมองผ่านมาตรฐานด้วยตัวเอง แต่ฉันไม่สามารถจัดส่วนต่างๆ ให้เป็นคำตอบที่สอดคล้องกันได้ ฉันจะให้รางวัล - person Snow; 25.09.2019

ลองเปลี่ยนดู

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(-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);
	}


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">

person Musevarg    schedule 04.09.2019
comment
สิ่งนี้ใช้ไม่ได้สำหรับฉัน คุณใช้เบราว์เซอร์ใดอยู่ - person Himmators; 05.09.2019