如何在画布中绘制一条带有背景图像的线条

时间:2014-01-31 15:33:44

标签: javascript html5 canvas

我正在尝试在画布上绘制一条线(我可以这样做),但我想使用背景图像在线上放置重复图案(除非有另一种方法将重复的背景图像放在一条线上在画布?)。

如何使用背景图像绘制线条?

我理解剪辑的概念,但这似乎只适用于形状...而不是笔画。有任何想法吗?

这是我尝试的一个方面 http://jsfiddle.net/Z9cd7/

    function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };
})();

var radius = 50;
var x = 100;
var dx = 10;
var y = 100;
var dy = 10;
var delay = 10;
var img = new Image();
img.onload = function () {
    var canvas1 = document.getElementById("image");
    var ctxImg = canvas1.getContext("2d");
    ctxImg.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);

    /*
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.beginPath();
    ctx.arc(100, 100, radius, 0, 2 * Math.PI, false);
    ctx.clip();
    ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
    ctx.restore();
    */
    ctx.moveTo(0,0)
    ctx.lineTo(100,100)
    ctx.lineWidth = 10;
    ctx.stroke()

    ctx.clip();
    ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
    ctx.restore();

    //animate();
}
img.src = "http://lh3.ggpht.com/_Z-i7eF_ACGI/TRxpFywLCxI/AAAAAAAAAD8/ACsxiuO_C1g/house%20vector.png";

4 个答案:

答案 0 :(得分:3)

我看到两个解决方案:

代码就是这个,基本上你想要一个w1 = w2的varLine(相同的开始/结束厚度);

// varLine : draws a line from A(x1,y1) to B(x2,y2)
// that starts with a w1 width and ends with a w2 width.
// relies on fillStyle for its color.
// ctx is a valid canvas's context2d.
function varLine(ctx, x1, y1, x2, y2, w1, w2) {
    var dx = (x2 - x1);
    var dy = (y2 - y1);
    w1 /= 2; // we only use w1/2 and w2/2 for computations.
    w2 /= 2;
    // length of the AB vector
    var length = Math.sqrt(sq(dx) + sq(dy));
    if (!length) return; // exit if zero length
    var shiftx = -dy * w1 / length; // compute AA1 vector's x
    var shifty = dx * w1 / length; // compute AA1 vector's y
    ctx.beginPath();
    ctx.moveTo(x1 + shiftx, y1 + shifty);
    ctx.lineTo(x1 - shiftx, y1 - shifty); // draw A1A2
    shiftx = -dy * w2 / length; // compute BB1 vector's x
    shifty = dx * w2 / length; // compute BB1 vector's y
    ctx.lineTo(x2 - shiftx, y2 - shifty); // draw A2B1
    ctx.lineTo(x2 + shiftx, y2 + shifty); // draw B1B2
    ctx.closePath(); // draw B2A1
    ctx.fill();
}
  • 第二种解决方案非常快:使用globalCompositeOperation模式为您进行剪裁。 例如画线,使用'source-in',然后在线的顶部绘制图像 这非常方便,但这里的问题是,只有在画线之前画布是干净的,它才会起作用。如果您可以自由选择绘图顺序,这不是问题,否则,您必须在临时画布中绘制线条,然后在主画布上绘制画布。

更新的小提琴在这里:  http://jsfiddle.net/gamealchemist/Z9cd7/1/

enter image description here

编辑:重复图像的小提琴: http://jsfiddle.net/gamealchemist/Z9cd7/2/

enter image description here

答案 1 :(得分:2)

我有点迟了但是由于不需要同时使用剪​​裁或计算向量,你可以考虑使用内置的支持(这更快),只需设置一个带有图像模式的笔触样式作为样式: / p>

var pattern = ctx.createPattern(image, 'repeat');  /// create pattern
ctx.strokeStyle = pattern;                         /// set as stroke style

ctx.moveTo(10, 10);
ctx.lineTo(200, 200);
ctx.lineWidth = 10;
ctx.stroke();                           /// strokes with the image as background

Demo 1 here

Pattern as stroke

如果你想改变图案尺寸,只需改变你在这种情况下使用的画布大小(“image”):

<canvas id="image" width=100 height=100></canvas>

并在onload处理程序中进行修改,以便缩放图像以适合画布:

ctxImg.drawImage(img, 0, 0, canvas1.width, canvas1.height);

Demo 2 here

Smaller pattern

如果您需要在绘制时调整图案的位置,可以使用translate()使用首先翻译的delta值,然后减去要用图案绘制的线条的位置 - 将字符保持在与翻译前相同的位置,但移动模式本身:

ctx.translate(dx, dy);
ctx.moveTo(x1 - dx, y1 - dy);
ctx.lineTo(x2 - dx, y2 - dy);
...

答案 2 :(得分: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} );
    }

之后,在每一行重复定位图像只是一点点数学:

    var dx=points[i].x-points[i-1].x;
    var dy=points[i].y-points[i-1].y;
    var length=Math.sqrt(dx*dx+dy*dy);
    var pctImage=imgWidth/length;
    for(var pct=pctImage/2;pct<1.00;pct+=pctImage){
         var pos=getLineXYatPercent(points[i-1],points[i],pct);
         ctx.drawImage(img,0,0,img.width,img.height,pos.x,pos.y,imgWidth,imgHeight);
    }   

演示:http://jsfiddle.net/m1erickson/R278u/

enter image description here

代码:

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    body{ background-color: lightgray; }
    #canvas{border:1px solid red;}
</style>
<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();
    var isDown=false;

    var points=[];
    points.push({x:0,y:0});
    points.push({x:100,y:125});
    points.push({x:200,y:75});
    points.push({x:300,y:100});

    imgWidth=20;
    imgHeight=20;

    var img=new Image();
    img.onload=function(){
        draw();
    }
    img.src="https://dl.dropboxusercontent.com/u/139992952/multple/house%20vector.png";

    function draw(){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(points[0].x,points[0].y);
        for(var i=1;i<points.length;i++){
            var p=points[i];
            var dx=points[i].x-points[i-1].x;
            var dy=points[i].y-points[i-1].y;
            var length=Math.sqrt(dx*dx+dy*dy);
            var pctImage=imgWidth/length;
            for(var pct=pctImage/2;pct<1.00;pct+=pctImage){
                var pos=getLineXYatPercent(points[i-1],points[i],pct);
                ctx.drawImage(img,0,0,img.width,img.height,pos.x,pos.y,imgWidth,imgHeight);
            }   
        }
    }

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

}); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

答案 3 :(得分:0)

你不是只是用第二个drawImage调用来覆盖所有东西吗?

编辑:你是,但这不是你的意思,尝试开始和关闭路径

 ctx.beginPath();
 ctx.moveTo(0,0)
 ctx.lineTo(100,100)
 ctx.lineTo(100,0);
 ctx.closePath()
 ctx.lineWidth = 10;
 ctx.stroke();
 ctx.clip();

 ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);