仅旋转画布中的图像

时间:2017-04-28 18:50:32

标签: javascript html5 image canvas rotation

我正在尝试在画布内旋转图像。

Here's my Fiddle: https://jsfiddle.net/kevinludwig11/s6rgpjm9/

我尝试使用保存和恢复,但路径也在旋转。

猎鹰应该朝着他的脸飞去并改变角落里的角度。

有人能帮助我吗?

编辑:我找到的一个解决方案:每次旋转将图像保存360次,并将每张图像加载到正确的位置。但我认为这不是最聪明的解决方案。

1 个答案:

答案 0 :(得分:0)

Canvas 2D图像外观变换。

无需创建360度图像即可旋转单个图像。你也有一些不正确的做法。

代码问题

  • 仅加载图像一次。每次渲染时都会加载它。
  • 自行使用requestAnimationFrame。将它放在计时器中会使其使用完全多余。
  • 如果您发现自己输入了很长的数字列表,特别是如果您在其他代码段中重复这些数字,您应该使用单个商店来保存所有内容。例如,你的路径都是手工编码的。将它们移动到一个数组中,然后迭代数组以获取路径所需的各种内容。十大编程规则之一。 “不要重复/复制任何东西。”

外观变换

要做鸟,你需要得到它朝向的方向,所以我在鸟的前面的曲线上添加了第二个点。有了这两点(鸟pos和lookat pos),我就使用lookat方向创建一个变换作为变换的xAxis。参见函数drawImageLookat(image,pos,lookat)我发现图像不是沿X轴,所以在找到外观变换后我将鸟旋转90度。

Lookat函数

// function assumes front (forward) of image is along the x axis to the right
function drawImageLookat(image, point, lookat ) {
    var xAx,xAy; // vector for x Axis of image
    var x,y;
    x = lookat.x - point.x;
    y = lookat.y - point.y;
    var dist = Math.max(0.01,Math.sqrt(x * x + y * y)); // Math.max to avoid zero which will create NaN
    xAx = x / dist; // get x component of x Axis
    xAy = y / dist; // get y component of x Axis
    // y axis is at 90 deg so dont need y axis vector
    ctx.setTransform(   // position the image using transform
        xAx, xAy, // set direction of x Axis
        -xAy, xAx, // set direction oy y axis
        point.x, point.y
    );   
    ctx.drawImage(image, -image.width / 2, -image.height / 2);
}

小提琴演示。

我从小提琴https://jsfiddle.net/kevinludwig11/s6rgpjm9/中获取的代码,并根据您的问题进行了修改。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// only load image once
var birdImage = new Image();
birdImage.src = 'http://www.happy-innovation.de/images/Falke_Flug.png';
birdImage.onload = function(){animate()}; // start animation when image has loaded
// set starting values
var speed = 0.25
var percent = speed;
var direction = speed;
var length = 300;

function animate() {
    ctx.setTransform(1,0,0,1,0,0); // restore default transform incase its not
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    percent += direction;
    // need to keep the position away from the ends as there is no lookat beyond the path.
    if(percent >= length - speed){
        percent = length- speed;
        direction = -speed;
    }else if(percent <= speed){
        percent = speed;
        direction = speed;
    }

    draw(percent,direction);
    requestAnimationFrame(animate);
}
function P(x,y){return {x,y}}; // quick way to create a point
var paths = [
    {col : 'red',   points : [P(100, 200), P(600, 350),  P( 700, 400)]},
    {col : "green", points : [P(700, 400), P( 900, 500), P( 200, 600), P( 950, 900)]},
    {col : "blue",  points : [P(950, 900), P(1200, 950), P( 300, 200), P( 150, 1200)]},
    {col : "brown", points : [P(150, 1200),P( 120, 1700),P( 1000, 700),P(850, 1500)]},
    {col : "Purple",points : [P(850, 1500),P(800, 1900), P( 200, 900), P( 250, 1800)]},
    {col : "yellow", points : [P(250, 1800),P(250, 1950), P( 600, 1500),P(950, 1800)]},
]
// draw the current frame based on sliderValue
function draw(sliderValue,direction) {
    var getPos = false; // true if need pos on current curve
    var getForwardPos = false; // true if need pos on current curve
    var percent,percent1; // get the percentage on curves
    var birdPos;  // get bird pos
    var birdLookAtPos; // get bird look at pos
    ctx.lineWidth = 5;
    for(var i = 0; i < paths.length; i ++){
        var path = paths[i]; // get a path from array
        var p = path.points;
        ctx.strokeStyle = path.col;
        ctx.beginPath();
        ctx.moveTo(p[0].x,p[0].y);
        if(sliderValue >= i * 50 && sliderValue < (i+1) * 50){
            getPos = true;
            percent = (sliderValue % 50) / 50;
        }   
        if(sliderValue + direction >= i * 50 && sliderValue + direction < (i+1) * 50){
            getForwardPos = true;
            percent1 = ((sliderValue + direction) % 50) / 50;
        }
        if(p.length > 3){
            ctx.bezierCurveTo(p[1].x,p[1].y,p[2].x,p[2].y,p[3].x,p[3].y);
            if(getPos){
                birdPos = getCubicBezierXYatPercent(p[0],p[1],p[2],p[3],percent);
                getPos = false;
            }
            if(getForwardPos){
                birdLookAtPos = getCubicBezierXYatPercent(p[0],p[1],p[2],p[3],percent1);
                getForwardPos = false;
            }
        }else{
            ctx.quadraticCurveTo(p[1].x,p[1].y,p[2].x,p[2].y);
            if(getPos){
                birdPos = getQuadraticBezierXYatPercent(p[0],p[1],p[2],percent);
                getPos = false;
            }
            if(getForwardPos){
                birdLookAtPos = getQuadraticBezierXYatPercent(p[0],p[1],p[2],percent1);
                getForwardPos = false;
            }
        }
        ctx.stroke();
    }
    drawImageLookingAt(birdImage,birdPos,birdLookAtPos);

}
function drawImageLookingAt(image, point, lookat ) {
    if(lookat === undefined){ // if no lookat then exit or it will crash.
        return;
    }
    var xAx,xAy; // vector for x Axis of image
    var x,y;
    x = lookat.x - point.x;
    y = lookat.y - point.y;
    var dist = Math.max(0.01,Math.sqrt(x * x + y * y)); // Math.max to avoid zero which will create NaN
    xAx = x / dist; // get x component of x Axis
    xAy = y / dist; // get y component of x Axis
    // y axis is at 90 deg so dont need y axis vector
    ctx.setTransform(   // position the image using transform
        xAx, xAy, // set direction of x Axis
        -xAy, xAx, // set direction oy y axis
        point.x, point.y
    );   
    // bird is pointing in the wrong direction. Not along x axis
    // so rotate the image 90 deg clockwise
    ctx.rotate(Math.PI / 2);
    ctx.drawImage(image, -image.width / 2, -image.height / 2);
    ctx.setTransform(1,0,0,1,0,0); // Restore default Not really needed if you only use setTransform to do transforms
                                   // but in case you use transform, rotate, translate or scale you need to reset the
                                   // transform.
}

// line: percent is 0-1
function getLineXYatPercent(startPt, endPt, percent) {
    var dx = endPt.x - startPt.x;
    var dy = endPt.y - startPt.y;
    var X = startPt.x + dx * percent;
    var Y = startPt.y + dy * percent;
    return ({
        x: X,
        y: Y
    });
}

// quadratic bezier: percent is 0-1
function getQuadraticBezierXYatPercent(startPt, controlPt, endPt, percent) {
    var x = Math.pow(1 - percent, 2) * startPt.x + 2 * (1 - percent) * percent * controlPt.x + Math.pow(percent, 2) * endPt.x;
    var y = Math.pow(1 - percent, 2) * startPt.y + 2 * (1 - percent) * percent * controlPt.y + Math.pow(percent, 2) * endPt.y;
    return ({
        x: x,
        y: y
    });
}

// cubic bezier percent is 0-1
function getCubicBezierXYatPercent(startPt, controlPt1, controlPt2, endPt, percent) {
    var x = CubicN(percent, startPt.x, controlPt1.x, controlPt2.x, endPt.x);
    var y = CubicN(percent, startPt.y, controlPt1.y, controlPt2.y, endPt.y);
    return ({
        x: x,
        y: y
    });
}

// cubic helper formula at percent distance
function CubicN(pct, a, b, c, d) {
    var t2 = pct * pct;
    var t3 = t2 * pct;
    return a + (-a * 3 + pct * (3 * a - a * pct)) * pct + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct + (c * 3 - c * 3 * pct) * t2 + d * t3;
}
<canvas height="1961" width="1000" id="canvas"></canvas>