【问题标题】:rotate only an image in a canvas仅旋转画布中的图像
【发布时间】:2017-09-26 23:26:28
【问题描述】:

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

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

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

猎鹰应该面朝飞行并改变角落的角度。

谁能帮帮我?

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

【问题讨论】:

    标签: javascript html image canvas rotation


    【解决方案1】:

    Canvas 2D 图像外观变换。

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

    代码问题

    • 只加载一次图像。每次渲染时您都在加载它。
    • 单独使用 requestAnimationFrame。将它放在计时器中会使其使用完全多余。
    • 如果您发现自己在输入一长串数字,尤其是在其他代码部分重复这些数字时,您应该使用单个存储来保存所有内容。例如,您的路径都是手工编码的。将它们移动到一个数组中,然后迭代数组以获取您需要对路径执行的各种操作。十大编程规则之一。 “不要重复/重复任何事情。”

    外观变换

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

    查看函数

    // 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;
    }
    &lt;canvas height="1961" width="1000" id="canvas"&gt;&lt;/canvas&gt;

    【讨论】:

      猜你喜欢
      • 2015-10-01
      • 2016-03-13
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      • 1970-01-01
      • 2020-07-11
      相关资源
      最近更新 更多