使用 JavaScript 三角函数缩放旋转图像以填充 HTML5 Canvas?
Scale rotated image to fill HTML5 Canvas using JavaScript trigonometry?
下面是我目前使用的代码。通过 0
旋转,图像会正确缩放以填充 canvas。 (类似于 background-size: cover
,除了在 Canvas 上使用 JavaScript)
我正在尝试添加具有以下功能的旋转功能。
旋转时保持图像居中。我尝试在 translate
中使用 width / 2
,然后在 drawImage
中使用相反的方法,但如您所见,图像没有保持居中。我不确定这是否与我之前的 x
和 y
居中代码冲突,或者这里是否需要三角函数?
自动进一步缩放图像以覆盖 canvas。这些是任意旋转,而不是 90 度增量。除了填充 canvas 角所必需的以外,我不想裁剪任何图像。这比我过去处理的要复杂得多。
我认为这可以用Math.sin
和Math.cos
来完成,但是我已经很长时间没有使用它们了。我特别不确定如何实现#2。任何帮助,将不胜感激。
var canvas = document.querySelector('canvas')
var context = canvas.getContext('2d')
var image = new Image()
image.src = 'http://i.stack.imgur.com/7FsbT.jpg'
image.onload = function () {
var maxScaleX = canvas.width / image.width
var maxScaleY = canvas.height / image.height
scale = maxScaleX > maxScaleY ? maxScaleX : maxScaleY
var width = image.width * scale
var height = image.height * scale
var x = (width - canvas.width) / -2
var y = (height - canvas.height) / -2
var degrees = 30
context.setTransform(1, 0, 0, 1, 0, 0) // reset previous translate and/or rotate
context.translate(width / 2, height / 2)
context.rotate(degrees * Math.PI / 180)
context.drawImage(image, x - width / 2, y - height / 2, width, height)
}
<canvas width="350" height="150" style="border: solid 1px black"></canvas>
才能正常工作。
我缩短了代码并简化了我的用例。您应该能够将 function drawBestFit()
包含到您的应用程序中,并使用它来填充任何 canvas 和任何已加载的图像。
为了更好地理解其工作原理,请查看 - 特别是底部的演示片段。
var canvas = document.querySelector('canvas')
var context = canvas.getContext('2d')
var image = new Image()
image.src = 'http://i.stack.imgur.com/7FsbT.jpg'
image.onload = function() {
var degrees = 0
loop()
function loop() {
degrees += .5
drawBestFit(context, degrees * Math.PI / 180, image)
requestAnimationFrame(loop)
}
function drawBestFit(ctx, angle, image) {
var dist = Math.sqrt(Math.pow(canvas.width, 2) + Math.pow(canvas.height, 2))
var diagAngle = Math.asin(canvas.height / dist)
var a1 = ((angle % (Math.PI * 2)) + Math.PI * 4) % (Math.PI * 2)
if (a1 > Math.PI)
a1 -= Math.PI
if (a1 > Math.PI / 2 && a1 <= Math.PI)
a1 = (Math.PI / 2) - (a1 - (Math.PI / 2))
var ang1 = Math.PI / 2 - diagAngle - Math.abs(a1)
var ang2 = Math.abs(diagAngle - Math.abs(a1))
var scale1 = Math.cos(ang1) * dist / image.height
var scale2 = Math.cos(ang2) * dist / image.width
var scale = Math.max(scale1, scale2)
var dx = Math.cos(angle) * scale
var dy = Math.sin(angle) * scale
ctx.setTransform(dx, dy, -dy, dx, canvas.width / 2, canvas.height / 2)
ctx.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height)
ctx.setTransform(1, 0, 0, 1, 0, 0) // reset transformations when done
}
}
<canvas width="350" height="200" style="border: solid 1px black"></canvas>
下面是我目前使用的代码。通过 0
旋转,图像会正确缩放以填充 canvas。 (类似于 background-size: cover
,除了在 Canvas 上使用 JavaScript)
我正在尝试添加具有以下功能的旋转功能。
旋转时保持图像居中。我尝试在
translate
中使用width / 2
,然后在drawImage
中使用相反的方法,但如您所见,图像没有保持居中。我不确定这是否与我之前的x
和y
居中代码冲突,或者这里是否需要三角函数?自动进一步缩放图像以覆盖 canvas。这些是任意旋转,而不是 90 度增量。除了填充 canvas 角所必需的以外,我不想裁剪任何图像。这比我过去处理的要复杂得多。
我认为这可以用Math.sin
和Math.cos
来完成,但是我已经很长时间没有使用它们了。我特别不确定如何实现#2。任何帮助,将不胜感激。
var canvas = document.querySelector('canvas')
var context = canvas.getContext('2d')
var image = new Image()
image.src = 'http://i.stack.imgur.com/7FsbT.jpg'
image.onload = function () {
var maxScaleX = canvas.width / image.width
var maxScaleY = canvas.height / image.height
scale = maxScaleX > maxScaleY ? maxScaleX : maxScaleY
var width = image.width * scale
var height = image.height * scale
var x = (width - canvas.width) / -2
var y = (height - canvas.height) / -2
var degrees = 30
context.setTransform(1, 0, 0, 1, 0, 0) // reset previous translate and/or rotate
context.translate(width / 2, height / 2)
context.rotate(degrees * Math.PI / 180)
context.drawImage(image, x - width / 2, y - height / 2, width, height)
}
<canvas width="350" height="150" style="border: solid 1px black"></canvas>
我缩短了代码并简化了我的用例。您应该能够将 function drawBestFit()
包含到您的应用程序中,并使用它来填充任何 canvas 和任何已加载的图像。
为了更好地理解其工作原理,请查看
var canvas = document.querySelector('canvas')
var context = canvas.getContext('2d')
var image = new Image()
image.src = 'http://i.stack.imgur.com/7FsbT.jpg'
image.onload = function() {
var degrees = 0
loop()
function loop() {
degrees += .5
drawBestFit(context, degrees * Math.PI / 180, image)
requestAnimationFrame(loop)
}
function drawBestFit(ctx, angle, image) {
var dist = Math.sqrt(Math.pow(canvas.width, 2) + Math.pow(canvas.height, 2))
var diagAngle = Math.asin(canvas.height / dist)
var a1 = ((angle % (Math.PI * 2)) + Math.PI * 4) % (Math.PI * 2)
if (a1 > Math.PI)
a1 -= Math.PI
if (a1 > Math.PI / 2 && a1 <= Math.PI)
a1 = (Math.PI / 2) - (a1 - (Math.PI / 2))
var ang1 = Math.PI / 2 - diagAngle - Math.abs(a1)
var ang2 = Math.abs(diagAngle - Math.abs(a1))
var scale1 = Math.cos(ang1) * dist / image.height
var scale2 = Math.cos(ang2) * dist / image.width
var scale = Math.max(scale1, scale2)
var dx = Math.cos(angle) * scale
var dy = Math.sin(angle) * scale
ctx.setTransform(dx, dy, -dy, dx, canvas.width / 2, canvas.height / 2)
ctx.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height)
ctx.setTransform(1, 0, 0, 1, 0, 0) // reset transformations when done
}
}
<canvas width="350" height="200" style="border: solid 1px black"></canvas>