简体   繁体   English

在 html5 的画布上绘制扭曲的图像

[英]Draw distorted image on html5's canvas

Is it possible, and if so how, to draw images with its four corners distorted to a non rectangular shape.是否有可能,如果可以,如何绘制四个角扭曲成非矩形的图像。 For example if you were wanting to draw the image as if it had been rotated around in 3d space.例如,如果您想要绘制图像,就好像它在 3d 空间中旋转了一样。

I created a simple 4 point transform based on Thatcher Ulrich's code ( http://tulrich.com/geekstuff/canvas/perspective.html ).我基于 Thatcher Ulrich 的代码 ( http://tulrich.com/geekstuff/canvas/perspective.html ) 创建了一个简单的 4 点变换。 This version just extracts the small bit of triangle code and handles the geometry subdivision for proper transformation.这个版本只是提取了一小部分三角形代码并处理几何细分以进行适当的转换。 Enjoy!享受!

4 画布中的点变换

http://jsfiddle.net/mrbendel/6rbtde5t/1/ http://jsfiddle.net/mrbendel/6rbtde5t/1/

var controls = [];
var canvas;
var context;
var image;
var triangles = [];
var dirtyTriangles = true;

var rand = function(s,e) {
    return Math.random() * (e-s) + s;
}

// dom ready
$(document).ready(function() {
    image = new Image();
    $(image).load(function() {
        setInterval(draw, 1000 / 60);
    });
    $(image).attr('src', 'http://media.giphy.com/media/NWb6sWXQQTqwg/giphy.gif');

    canvas = document.createElement('canvas');
    $(canvas).attr('width', 500);
    $(canvas).attr('height', 500);
    $('body').append(canvas);

    context = canvas.getContext('2d');

    //
    for (var i = 0; i < 4; ++i) {
        var control = document.createElement('div');
        $(control).addClass('node');
        $('body').append(control);
        controls.push(control);
    }

    $(controls[0]).css('left', rand(25, 225));
    $(controls[0]).css('top', rand(25, 225));

    $(controls[1]).css('left', rand(250, 475));
    $(controls[1]).css('top', rand(25, 225));

    $(controls[2]).css('left', rand(250, 475));
    $(controls[2]).css('top', rand(250, 475));

    $(controls[3]).css('left', rand(25, 225));
    $(controls[3]).css('top', rand(250, 475));

    $('body').mousedown(function(e) {
        if ($(e.target).hasClass('node')) {
            var node = e.target;

            $('body').mousemove(function(e) {
                var x = e.pageX;
                var y = e.pageY;
                $(node).css('left', x);
                $(node).css('top', y);
                dirtyTriangles = true;
            });

            $('body').mouseup(function(e) {
                $('body').off( "mousemove" );
                $('body').off( "mouseup" );
            });
        }
    });
});

var draw = function() {
    context.clearRect(0,0,500,500);

    var render = function(wireframe, image, tri) {

        if (wireframe) {
            context.strokeStyle = "black";
            context.beginPath();
            context.moveTo(tri.p0.x, tri.p0.y);
            context.lineTo(tri.p1.x, tri.p1.y);
            context.lineTo(tri.p2.x, tri.p2.y);
            context.lineTo(tri.p0.x, tri.p0.y);
            context.stroke();
            context.closePath();
        }

        if (image) {
            drawTriangle(context, image,
                         tri.p0.x, tri.p0.y,
                         tri.p1.x, tri.p1.y,
                         tri.p2.x, tri.p2.y,
                         tri.t0.u, tri.t0.v,
                         tri.t1.u, tri.t1.v,
                         tri.t2.u, tri.t2.v);
        }
    }

    if (dirtyTriangles) {
        dirtyTriangles = false;
        calculateGeometry();
    }

    for (triangle of triangles) {
        render(true, image, triangle);
    }
}

var calculateGeometry = function() {
    // clear triangles out
    triangles = [];

    // generate subdivision
    var subs = 7; // vertical subdivisions
    var divs = 7; // horizontal subdivisions

    var p1 = new Point(parseInt($(controls[0]).css('left')) + 6, parseInt($(controls[0]).css('top')) + 6);
    var p2 = new Point(parseInt($(controls[1]).css('left')) + 6, parseInt($(controls[1]).css('top')) + 6);
    var p3 = new Point(parseInt($(controls[2]).css('left')) + 6, parseInt($(controls[2]).css('top')) + 6);
    var p4 = new Point(parseInt($(controls[3]).css('left')) + 6, parseInt($(controls[3]).css('top')) + 6);

    var dx1 = p4.x - p1.x;
    var dy1 = p4.y - p1.y;
    var dx2 = p3.x - p2.x;
    var dy2 = p3.y - p2.y;

    var imgW = image.naturalWidth;
    var imgH = image.naturalHeight;

    for (var sub = 0; sub < subs; ++sub) {
        var curRow = sub / subs;
        var nextRow = (sub + 1) / subs;

        var curRowX1 = p1.x + dx1 * curRow;
        var curRowY1 = p1.y + dy1 * curRow;

        var curRowX2 = p2.x + dx2 * curRow;
        var curRowY2 = p2.y + dy2 * curRow;

        var nextRowX1 = p1.x + dx1 * nextRow;
        var nextRowY1 = p1.y + dy1 * nextRow;

        var nextRowX2 = p2.x + dx2 * nextRow;
        var nextRowY2 = p2.y + dy2 * nextRow;

        for (var div = 0; div < divs; ++div) {
            var curCol = div / divs;
            var nextCol = (div + 1) / divs;

            var dCurX = curRowX2 - curRowX1;
            var dCurY = curRowY2 - curRowY1;
            var dNextX = nextRowX2 - nextRowX1;
            var dNextY = nextRowY2 - nextRowY1;

            var p1x = curRowX1 + dCurX * curCol;
            var p1y = curRowY1 + dCurY * curCol;

            var p2x = curRowX1 + (curRowX2 - curRowX1) * nextCol;
            var p2y = curRowY1 + (curRowY2 - curRowY1) * nextCol;

            var p3x = nextRowX1 + dNextX * nextCol;
            var p3y = nextRowY1 + dNextY * nextCol;

            var p4x = nextRowX1 + dNextX * curCol;
            var p4y = nextRowY1 + dNextY * curCol;

            var u1 = curCol * imgW;
            var u2 = nextCol * imgW;
            var v1 = curRow * imgH;
            var v2 = nextRow * imgH;

            var triangle1 = new Triangle(
                new Point(p1x, p1y),
                new Point(p3x, p3y),
                new Point(p4x, p4y),
                new TextCoord(u1, v1),
                new TextCoord(u2, v2),
                new TextCoord(u1, v2)
            );

            var triangle2 = new Triangle(
                new Point(p1x, p1y),
                new Point(p2x, p2y),
                new Point(p3x, p3y),
                new TextCoord(u1, v1),
                new TextCoord(u2, v1),
                new TextCoord(u2, v2)
            );

            triangles.push(triangle1);
            triangles.push(triangle2);
        }
    }
}

// from http://tulrich.com/geekstuff/canvas/jsgl.js
var drawTriangle = function(ctx, im, x0, y0, x1, y1, x2, y2,
    sx0, sy0, sx1, sy1, sx2, sy2) {
    ctx.save();

    // Clip the output to the on-screen triangle boundaries.
    ctx.beginPath();
    ctx.moveTo(x0, y0);
    ctx.lineTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.closePath();
    //ctx.stroke();//xxxxxxx for wireframe
    ctx.clip();

    /*
    ctx.transform(m11, m12, m21, m22, dx, dy) sets the context transform matrix.

    The context matrix is:

    [ m11 m21 dx ]
    [ m12 m22 dy ]
    [  0   0   1 ]

    Coords are column vectors with a 1 in the z coord, so the transform is:
    x_out = m11 * x + m21 * y + dx;
    y_out = m12 * x + m22 * y + dy;

    From Maxima, these are the transform values that map the source
    coords to the dest coords:

    sy0 (x2 - x1) - sy1 x2 + sy2 x1 + (sy1 - sy2) x0
    [m11 = - -----------------------------------------------------,
    sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

    sy1 y2 + sy0 (y1 - y2) - sy2 y1 + (sy2 - sy1) y0
    m12 = -----------------------------------------------------,
    sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

    sx0 (x2 - x1) - sx1 x2 + sx2 x1 + (sx1 - sx2) x0
    m21 = -----------------------------------------------------,
    sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

    sx1 y2 + sx0 (y1 - y2) - sx2 y1 + (sx2 - sx1) y0
    m22 = - -----------------------------------------------------,
    sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

    sx0 (sy2 x1 - sy1 x2) + sy0 (sx1 x2 - sx2 x1) + (sx2 sy1 - sx1 sy2) x0
    dx = ----------------------------------------------------------------------,
    sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

    sx0 (sy2 y1 - sy1 y2) + sy0 (sx1 y2 - sx2 y1) + (sx2 sy1 - sx1 sy2) y0
    dy = ----------------------------------------------------------------------]
    sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0
  */

    // TODO: eliminate common subexpressions.
    var denom = sx0 * (sy2 - sy1) - sx1 * sy2 + sx2 * sy1 + (sx1 - sx2) * sy0;
    if (denom == 0) {
        return;
    }
    var m11 = -(sy0 * (x2 - x1) - sy1 * x2 + sy2 * x1 + (sy1 - sy2) * x0) / denom;
    var m12 = (sy1 * y2 + sy0 * (y1 - y2) - sy2 * y1 + (sy2 - sy1) * y0) / denom;
    var m21 = (sx0 * (x2 - x1) - sx1 * x2 + sx2 * x1 + (sx1 - sx2) * x0) / denom;
    var m22 = -(sx1 * y2 + sx0 * (y1 - y2) - sx2 * y1 + (sx2 - sx1) * y0) / denom;
    var dx = (sx0 * (sy2 * x1 - sy1 * x2) + sy0 * (sx1 * x2 - sx2 * x1) + (sx2 * sy1 - sx1 * sy2) * x0) / denom;
    var dy = (sx0 * (sy2 * y1 - sy1 * y2) + sy0 * (sx1 * y2 - sx2 * y1) + (sx2 * sy1 - sx1 * sy2) * y0) / denom;

    ctx.transform(m11, m12, m21, m22, dx, dy);

    // Draw the whole image.  Transform and clip will map it onto the
    // correct output triangle.
    //
    // TODO: figure out if drawImage goes faster if we specify the rectangle that
    // bounds the source coords.
    ctx.drawImage(im, 0, 0);
    ctx.restore();
};

// point class

var Point = function(x,y) {
    this.x = x?x:0;
    this.y = y?y:0;
}

var p = Point.prototype;

p.length = function(point) {
    point = point?point:new Point();
    var xs =0, ys =0;
    xs = point.x - this.x;
    xs = xs * xs;

    ys = point.y - this.y;
    ys = ys * ys;
    return Math.sqrt( xs + ys );
}

var TextCoord = function(u,v) {
    this.u = u?u:0;
    this.v = v?v:0;
}

var Triangle = function(p0, p1, p2, t0, t1, t2) {
    this.p0 = p0;
    this.p1 = p1;
    this.p2 = p2;

    this.t0 = t0;
    this.t1 = t1;
    this.t2 = t2;
}

The easiest way is to apply a transformation to the canvas before drawing the image.最简单的方法是在绘制图像之前对画布应用转换。

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#transformations http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#transformations

With skewing transformations you can make it look like it was drawn in perspective通过倾斜变换,您可以使它看起来像透视图

Here's a very simple example:这是一个非常简单的例子:

ctx.setTransform (1, -0.2, 0, 1, 0, 0);
ctx.drawImage(blah);

Check out this tutorial, it uses optical illusion to simulate perspective. 查看本教程,它使用光学错觉来模拟透视。 http://www.subshell.com/en/subshell/blog/image-manipulation-html5-canvas102.html http://www.subshel​​l.com/en/subshel​​l/blog/image-manipulation-html5-canvas102.html

You could try function transferPoint (xI, yI, source, destination) explicated here .您可以尝试此处说明的function transferPoint (xI, yI, source, destination)

Source and destination are the four points of source and destination rectangles.源和目标是源和目标矩形的四个点。 The code works for (SVG) path coordinates (curve and line), but with some modification should work also with pixels.该代码适用于(SVG)路径坐标(曲线和线),但经过一些修改后也适用于像素。

A number of commenters above have asked about hiding the triangles - do this and they'll disappear (for info: @erbridge, @Constantin Groß):上面的一些评论者询问了隐藏三角形 - 这样做,它们会消失(信息:@erbridge,@Constantin Groß):

All credit for the following still goes to @AndyPoes, since this was all his suggestion - I'm just adding the completed version he suggested.以下所有功劳仍然归功于@AndyPoes,因为这是他的全部建议 - 我只是添加了他建议的完整版本。

Change this line:改变这一行:

render(true, image, triangle);

To this:对此:

render(false, image, triangle);

...the black triangles will have gone, but you'll see gaps between the triangles, so now do this: ...黑色三角形将消失,但您会看到三角形之间的间隙,所以现在执行以下操作:

Change this:改变这个:

var triangle1 = new Triangle(
            new Point(p1x, p1y),
            new Point(p3x, p3y),
            new Point(p4x, p4y),
            new TextCoord(u1, v1),
            new TextCoord(u2, v2),
            new TextCoord(u1, v2)
        );

        var triangle2 = new Triangle(
            new Point(p1x, p1y),
            new Point(p2x, p2y),
            new Point(p3x, p3y),
            new TextCoord(u1, v1),
            new TextCoord(u2, v1),
            new TextCoord(u2, v2)
        );

To this instead:对此:

            var triangle1 = new Triangle(
            new Point(p1x-1, p1y),
            new Point(p3x+2, p3y+1),
            new Point(p4x-1, p4y+1),
            new TextCoord(u1, v1),
            new TextCoord(u2, v2),
            new TextCoord(u1, v2)
        );

        var triangle2 = new Triangle(
            new Point(p1x-2, p1y),
            new Point(p2x+1, p2y),
            new Point(p3x+1, p3y+1),
            new TextCoord(u1, v1),
            new TextCoord(u2, v1),
            new TextCoord(u2, v2)
        );

....and the gaps will be closed. ....并且差距将被关闭。

New fiddle = fiddler off the roof新小提琴 =屋顶上的小提琴手

Full code is here:完整代码在这里:

var controls = [];
var canvas;
var context;
var image;
var triangles = [];
var dirtyTriangles = false;

var rand = function(s,e) {
    return Math.random() * (e-s) + s;
}

// dom ready
$(document).ready(function() {
image = new Image();
$(image).load(function() {
    setInterval(draw, 1000 / 60);
});
$(image).attr('src', 'https://images.unsplash.com/photo-1500964757637-c85e8a162699?ixlib=rb-1.2.1&q=80&fm=jpg');

canvas = document.createElement('canvas');
$(canvas).attr('width', 500);
$(canvas).attr('height', 500);
$('body').append(canvas);

context = canvas.getContext('2d');

//
for (var i = 0; i < 4; ++i) {
    var control = document.createElement('div');
    $(control).addClass('node');
    $('body').append(control);
    controls.push(control);
}

$(controls[0]).css('left', rand(25, 225));
$(controls[0]).css('top', rand(25, 225));

$(controls[1]).css('left', rand(250, 475));
$(controls[1]).css('top', rand(25, 225));

$(controls[2]).css('left', rand(250, 475));
$(controls[2]).css('top', rand(250, 475));

$(controls[3]).css('left', rand(25, 225));
$(controls[3]).css('top', rand(250, 475));

$('body').mousedown(function(e) {
    if ($(e.target).hasClass('node')) {
        var node = e.target;

        $('body').mousemove(function(e) {
            var x = e.pageX;
            var y = e.pageY;
            $(node).css('left', x);
            $(node).css('top', y);
            dirtyTriangles = true;
        });

        $('body').mouseup(function(e) {
            $('body').off( "mousemove" );
            $('body').off( "mouseup" );
        });
    }
});
});

var draw = function() {
context.clearRect(0,0,500,500);

var render = function(wireframe, image, tri) {
    
    if (wireframe) {
        context.strokeStyle = "black";
        context.beginPath();
        context.moveTo(tri.p0.x, tri.p0.y);
        context.lineTo(tri.p1.x, tri.p1.y);
        context.lineTo(tri.p2.x, tri.p2.y);
        context.lineTo(tri.p0.x, tri.p0.y);
        context.stroke();
        context.closePath();
    }

    if (image) {
        drawTriangle(context, image,
                     tri.p0.x, tri.p0.y,
                     tri.p1.x, tri.p1.y,
                     tri.p2.x, tri.p2.y,
                     tri.t0.u, tri.t0.v,
                     tri.t1.u, tri.t1.v,
                     tri.t2.u, tri.t2.v);
    }
}

if (dirtyTriangles) {
    dirtyTriangles = false;
    calculateGeometry();
}

for (triangle of triangles) {
    render(true, image, triangle);
}
}

var calculateGeometry = function() {
// clear triangles out
triangles = [];

// generate subdivision
var subs = 7; // vertical subdivisions
var divs = 7; // horizontal subdivisions

var p1 = new Point(parseInt($(controls[0]).css('left')) + 6, parseInt($(controls[0]).css('top')) + 6);
var p2 = new Point(parseInt($(controls[1]).css('left')) + 6, parseInt($(controls[1]).css('top')) + 6);
var p3 = new Point(parseInt($(controls[2]).css('left')) + 6, parseInt($(controls[2]).css('top')) + 6);
var p4 = new Point(parseInt($(controls[3]).css('left')) + 6, parseInt($(controls[3]).css('top')) + 6);

var dx1 = p4.x - p1.x;
var dy1 = p4.y - p1.y;
var dx2 = p3.x - p2.x;
var dy2 = p3.y - p2.y;

var imgW = image.naturalWidth;
var imgH = image.naturalHeight;

for (var sub = 0; sub < subs; ++sub) {
    var curRow = sub / subs;
    var nextRow = (sub + 1) / subs;

    var curRowX1 = p1.x + dx1 * curRow;
    var curRowY1 = p1.y + dy1 * curRow;
    
    var curRowX2 = p2.x + dx2 * curRow;
    var curRowY2 = p2.y + dy2 * curRow;

    var nextRowX1 = p1.x + dx1 * nextRow;
    var nextRowY1 = p1.y + dy1 * nextRow;
    
    var nextRowX2 = p2.x + dx2 * nextRow;
    var nextRowY2 = p2.y + dy2 * nextRow;

    for (var div = 0; div < divs; ++div) {
        var curCol = div / divs;
        var nextCol = (div + 1) / divs;

        var dCurX = curRowX2 - curRowX1;
        var dCurY = curRowY2 - curRowY1;
        var dNextX = nextRowX2 - nextRowX1;
        var dNextY = nextRowY2 - nextRowY1;

        var p1x = curRowX1 + dCurX * curCol;
        var p1y = curRowY1 + dCurY * curCol;

        var p2x = curRowX1 + (curRowX2 - curRowX1) * nextCol;
        var p2y = curRowY1 + (curRowY2 - curRowY1) * nextCol;

        var p3x = nextRowX1 + dNextX * nextCol;
        var p3y = nextRowY1 + dNextY * nextCol;

        var p4x = nextRowX1 + dNextX * curCol;
        var p4y = nextRowY1 + dNextY * curCol;

        var u1 = curCol * imgW;
        var u2 = nextCol * imgW;
        var v1 = curRow * imgH;
        var v2 = nextRow * imgH;

        var triangle1 = new Triangle(
            new Point(p1x-1, p1y),
            new Point(p3x+2, p3y+1),
            new Point(p4x-1, p4y+1),
            new TextCoord(u1, v1),
            new TextCoord(u2, v2),
            new TextCoord(u1, v2)
        );

        var triangle2 = new Triangle(
            new Point(p1x-2, p1y),
            new Point(p2x+1, p2y),
            new Point(p3x+1, p3y+1),
            new TextCoord(u1, v1),
            new TextCoord(u2, v1),
            new TextCoord(u2, v2)
        );

        triangles.push(triangle1);
        triangles.push(triangle2);
    }
}
}

// from http://tulrich.com/geekstuff/canvas/jsgl.js
var drawTriangle = function(ctx, im, x0, y0, x1, y1, x2, y2,
sx0, sy0, sx1, sy1, sx2, sy2) {
ctx.save();

// Clip the output to the on-screen triangle boundaries.
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
//ctx.stroke();//xxxxxxx for wireframe
ctx.clip();

/*
ctx.transform(m11, m12, m21, m22, dx, dy) sets the context transform matrix.

The context matrix is:

[ m11 m21 dx ]
[ m12 m22 dy ]
[  0   0   1 ]

Coords are column vectors with a 1 in the z coord, so the transform is:
x_out = m11 * x + m21 * y + dx;
y_out = m12 * x + m22 * y + dy;

From Maxima, these are the transform values that map the source
coords to the dest coords:

sy0 (x2 - x1) - sy1 x2 + sy2 x1 + (sy1 - sy2) x0
[m11 = - -----------------------------------------------------,
sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

sy1 y2 + sy0 (y1 - y2) - sy2 y1 + (sy2 - sy1) y0
m12 = -----------------------------------------------------,
sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

sx0 (x2 - x1) - sx1 x2 + sx2 x1 + (sx1 - sx2) x0
m21 = -----------------------------------------------------,
sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

sx1 y2 + sx0 (y1 - y2) - sx2 y1 + (sx2 - sx1) y0
m22 = - -----------------------------------------------------,
sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

sx0 (sy2 x1 - sy1 x2) + sy0 (sx1 x2 - sx2 x1) + (sx2 sy1 - sx1 sy2) x0
dx = ----------------------------------------------------------------------,
sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0

sx0 (sy2 y1 - sy1 y2) + sy0 (sx1 y2 - sx2 y1) + (sx2 sy1 - sx1 sy2) y0
dy = ----------------------------------------------------------------------]
sx0 (sy2 - sy1) - sx1 sy2 + sx2 sy1 + (sx1 - sx2) sy0
  */

// TODO: eliminate common subexpressions.
var denom = sx0 * (sy2 - sy1) - sx1 * sy2 + sx2 * sy1 + (sx1 - sx2) * sy0;
if (denom == 0) {
    return;
}
var m11 = -(sy0 * (x2 - x1) - sy1 * x2 + sy2 * x1 + (sy1 - sy2) * x0) / denom;
var m12 = (sy1 * y2 + sy0 * (y1 - y2) - sy2 * y1 + (sy2 - sy1) * y0) / denom;
var m21 = (sx0 * (x2 - x1) - sx1 * x2 + sx2 * x1 + (sx1 - sx2) * x0) / denom;
var m22 = -(sx1 * y2 + sx0 * (y1 - y2) - sx2 * y1 + (sx2 - sx1) * y0) / denom;
var dx = (sx0 * (sy2 * x1 - sy1 * x2) + sy0 * (sx1 * x2 - sx2 * x1) + (sx2 * sy1 - sx1 * sy2) * x0) / denom;
var dy = (sx0 * (sy2 * y1 - sy1 * y2) + sy0 * (sx1 * y2 - sx2 * y1) + (sx2 * sy1 - sx1 * sy2) * y0) / denom;

ctx.transform(m11, m12, m21, m22, dx, dy);

// Draw the whole image.  Transform and clip will map it onto the
// correct output triangle.
//
// TODO: figure out if drawImage goes faster if we specify the rectangle that
// bounds the source coords.
ctx.drawImage(im, 0, 0);
ctx.restore();
};

// point class

var Point = function(x,y) {
this.x = x?x:0;
this.y = y?y:0;
}

var p = Point.prototype;

p.length = function(point) {
    point = point?point:new Point();
    var xs =0, ys =0;
    xs = point.x - this.x;
    xs = xs * xs;

    ys = point.y - this.y;
    ys = ys * ys;
    return Math.sqrt( xs + ys );
}

var TextCoord = function(u,v) {
this.u = u?u:0;
this.v = v?v:0;
}

var Triangle = function(p0, p1, p2, t0, t1, t2) {
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;

this.t0 = t0;
this.t1 = t1;
this.t2 = t2;
}

@Steve , I noticed that the image is invisible on first render in your updated Fiddle. @Steve ,我注意到在您更新的 Fiddle 中第一次渲染时图像是不可见的。 It appears as soon as you start interacting with the corners however.但是,一旦您开始与角落互动,它就会出现。 See below见下文

Image is invisible on first render until you interact with the corners在您与角落互动之前,图像在第一次渲染时是不可见的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM