Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
741 views
in Technique[技术] by (71.8m points)

html - Canvas pattern offset

I'm trying to modify the origin of canvas pattern but can't achieve quite what I want.

I need to draw a line filled with a dotted pattern. Dotted pattern is created via createPattern (feeding it dynamically created canvas element).

The canvas (essentially a red dot) is created like so:

function getPatternCanvas() {
  var dotWidth = 20,
      dotDistance = 5,
      patternCanvas = document.createElement('canvas'),
      patternCtx = patternCanvas.getContext('2d');

  patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;

  // attempt #1:
  // patternCtx.translate(10, 10);

  patternCtx.fillStyle = 'red';
  patternCtx.beginPath();
  patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);
  patternCtx.closePath();
  patternCtx.fill();

  return patternCanvas;
}

Then a line is drawn using that pattern (canvas):

var canvasEl = document.getElementById('c');
var ctx = canvasEl.getContext('2d');
var pattern = ctx.createPattern(getPatternCanvas(), 'repeat');

// attempt #2
// ctx.translate(10, 10);

ctx.strokeStyle = pattern;
ctx.lineWidth = 30;

ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100, 100);
ctx.stroke();

So we get this:

enter image description here

Now, I'd like to offset the origin of those dots, say, by 10px. Translating pattern canvas doesn't help as then we don't get full dots:

enter image description here

And translating context of canvas itself doesn't help as that offsets the line, not the pattern itself:

enter image description here

Translating context doesn't seem to affect pattern origin.

Is there a way to modify offset of pattern itself?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Update Since this answer was posted there is now (since 2015/02) a local setTransform() on the CanvasPattern instance itself (see specs). It may not be available in all browsers yet (only Firefox supports it when this was written).

Method 1

You could offset the main canvas and add a delta value to the actual position of the line:

var offsetX = 10, offsetY = 10;
ctx.translate(offsetX, offsetY);
ctx.lineTo(x - offsetX, y - offsetY);
// ...

Example

(the demo only shows the pattern being translated, but of course, normally you would move the line together with it).

Line

etc. this way you cancel the translation for the line itself. But it introduces some overhead as the coordinates needs to be calculated each time unless you can cache the resulting value.

Method 2

The other way I can think of is to sort of create a pattern of the pattern it self. I.e. for the pattern canvas repeat the dot so that when you move it outside its boundary it is repeated in the opposite direction.

For example here the first square is the normal pattern, the second is the offset pattern described as method two and the third image uses the offset pattern for fill showing it will work.

The key is that the two patterns are of the same size and that the first pattern is repeated offset into this second version. The second version can then be used as fill on the main.

Example 2 (links broken)

Example 3 animated

Dots

var ctx = demo.getContext('2d'),
    pattern;

// create the pattern    
ctx.fillStyle = 'red';
ctx.arc(25, 25, 22, 0, 2*Math.PI);
ctx.fill();

// offset and repeat first pattern to base for second pattern
ctx = demo2.getContext('2d');
pattern = ctx.createPattern(demo, 'repeat');
ctx.translate(25, 25);
ctx.fillStyle = pattern;
ctx.fillRect(-25, -25, 50, 50);

// use second pattern to fill main canvas
ctx = demo3.getContext('2d');
pattern = ctx.createPattern(demo2, 'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 200, 200);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...