简体   繁体   English

如何在画布上绘制带有背景图像的线

[英]How to draw a line in canvas with a background image

I'm trying to draw a line in canvas (which I can do), but I want to put a repeating pattern on the line using a background image (unless there is another way to put a repeating background image on a line in canvas?). 我正在尝试在画布上画一条线(我可以这样做),但是我想使用背景图像在线条上放置重复图案(除非有另一种方法可以在画布上的线条上放置重复的背景图像? )。

How can I draw a line with a background image? 如何绘制带有背景图像的线?

I understand the concept of clipping, but that only seems to work with shapes... not with a stroke. 我了解剪切的概念,但似乎仅适用于形状...不适用于笔触。 Any ideas? 有任何想法吗?

Here is a jsfiddle of what I was trying http://jsfiddle.net/Z9cd7/ 这是我正在尝试的jsfiddle 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";

I see two solutions : 我看到两个解决方案:

The code is this one, basically you want a varLine with w1 = w2 (same start / end thickness) ; 代码是这样的,基本上你想要一个varLine w1 = w2(相同的开始/结束厚度);

// 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();
}
  • Second solution is very quick : use the globalCompositeOperation modes to do the clipping for you. 第二种解决方案非常快:使用globalCompositeOperation模式为您进行裁剪。 for instance draw the line, use 'source-in', then draw the image on top of the line. 例如画线,使用“ source-in”,然后在画线的顶部绘制图像。
    This is very handy, but the issue here is that it will work only if the canvas was clean before the line draw. 这非常方便,但是这里的问题是,只有在画线之前画布是干净的,它才能工作。 If you can choose freely drawing order, this is not an issue, otherwise, you'll have to draw the line in a temp canvas, then draw the canvas on the main canvas. 如果可以选择自由绘制的顺序,那么这不是问题,否则,您将不得不在临时画布中绘制线条,然后在主画布上绘制画布。

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

在此处输入图片说明

Edit : fiddle for the image with repetitions : http://jsfiddle.net/gamealchemist/Z9cd7/2/ 编辑:为重复的图像提琴: http : //jsfiddle.net/gamealchemist/Z9cd7/2/

在此处输入图片说明

I bit late but as there is no need to use neither clipping or calculating vectors you could perhaps consider using the built-in support for this (which is faster) by simply setting a stroke style with an image pattern as style: 我有点晚了,但是由于不需要使用裁剪或计算向量,您可以考虑通过简单地将笔触样式设置为图像样式作为样式来使用内置的支持(速度更快):

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 演示1在这里

图案为中风

If you want to change the pattern size just change the size of the canvas (" image ") you're using in this case: 如果要更改图案大小,只需更改在这种情况下使用的画布(“ image ”)的大小即可:

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

And with modification in your onload handler so image is scaled to fit the canvas: 并在onload处理程序中进行了修改,因此图像被缩放以适合画布:

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

Demo 2 here 演示2在这里

较小的图案

If you need to adjust the position of the pattern when drawing you can use translate() using a delta value which you first translate with and then subtract to the positions of the lines you want to draw with the pattern - that will keep the lines in the same position as before translating but move the pattern itself: 如果在绘制时需要调整图案的位置,则可以使用delta值来使用translate() ,首先将其转换,然后减去要使用图案绘制的线条的位置-这样可以使线条保持在与平移之前的位置相同,但会移动图案本身:

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

[ Using an image to draw a line ] [使用图像画线]

You can use this utility function to determine any percentage point along a line segment: 您可以使用此实用程序功能来确定线段上的任何百分比:

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

After that it's just a bit-of-math to repeatedly position your image along each line segement: 之后,沿着每条线段重复定位图像只是一点点的事:

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

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

在此处输入图片说明

Code: 码:

<!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>

Aren't you just drawing over everything with the second drawImage call? 您不是通过第二个drawImage调用来绘制所有内容吗?

edit : you are, but that's not what you mean, try beginning and closing the path 编辑:是的,但这不是您的意思,请尝试开始和结束路径

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

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

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