简体   繁体   English

将线性渐变应用于 CanvasPattern (Canvas API)

[英]Applying a linear gradient to a CanvasPattern (Canvas API)

I have a simple pattern that repeats and a gradient that extends beyond the dimensions of the pattern.我有一个重复的简单图案和一个超出图案尺寸的渐变。 It is possible to apply the linear gradient to the the rendered pattern as it repeats?是否可以在重复时将线性渐变应用于渲染的图案?

I tried the following, but it doesn't actually paint the gradient as I would expect:我尝试了以下方法,但它实际上并没有像我预期的那样绘制渐变:

 const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const gradient = context.createLinearGradient(0, 0, canvas.width, canvas.height); gradient.addColorStop(0, '#ff0000'); gradient.addColorStop(1, '#00ff00'); const patternCanvas = document.createElement('canvas'); const patternContext = patternCanvas.getContext('2d'); patternCanvas.height = 10; patternCanvas.width = 10; patternContext.fillStyle = gradient; // this doesn't work as expected patternContext.arc(5, 5, 2.5, 0, Math.PI * 2); patternContext.fill(); const pattern = context.createPattern(patternCanvas, 'repeat'); context.fillStyle = pattern; context.fillRect(0, 0, canvas.width, canvas.height);
 <canvas id = 'canvas'>

The CanvasPattern only holds a bitmap, ie pixels. CanvasPattern 只包含一个 bitmap,即像素。 You can not make it change dynamically other than transforming it (as in moving, scaling, rotating).除了变换它(如移动、缩放、旋转)之外,你不能让它动态变化。

So your idea of applying the same pattern shape, but with a gradient fill is not doable with a CanvasPattern only.因此,您应用相同图案形状但使用渐变填充的想法仅使用 CanvasPattern 是不可行的。

However, it's still quite simple to achieve, in two steps:但是,实现起来还是很简单的,分两步:

Every time you'll want to draw this gradient pattern, you'll first fill the pattern as a solid color, then change the composite operation to source-in, and then apply your gradient.每次您要绘制此渐变图案时,您首先将图案填充为纯色,然后将合成操作更改为 source-in,然后应用您的渐变。

 const ctx = createCanvasContext2d( 500, 500 ); document.body.append( ctx.canvas ); const pat = createPattern(); const grad = ctx.createLinearGradient( 0, 0, 500, 500); grad.addColorStop( 0, 'red' ); grad.addColorStop( 0.5, 'yellow' ); grad.addColorStop( 1, 'blue' ); ctx.arc( 250, 250, 250, 0, Math.PI*2 ); // first the pattern ctx.fillStyle = pat; ctx.fill(); // change the composite operation ctx.globalCompositeOperation = 'source-in'; // now draw the gradient ctx.fillStyle = grad; ctx.fill(); // reset to default ctx.globalCompositeOperation = 'source-over'; function createPattern() { // we create a small canvas context just for the pattern const pattern_ctx = createCanvasContext2d( 20, 20 ); // simply a black circle pattern_ctx.arc( 10, 10, 5, Math.PI*2, 0 ); pattern_ctx.fill(); return pattern_ctx.createPattern( pattern_ctx.canvas, 'repeat' ); } function createCanvasContext2d( width=300, height=width||150 ) { const canvas = document.createElement( 'canvas' ); canvas.width = width; canvas.height = height; return canvas.getContext( '2d' ); }

However the downside of this approach is that this operation requires you have a clear context, because everything that is not transparent when the gradient is drawn will get filled, and everything that is not in the filled area will get removed:然而这种方法的缺点是这个操作需要你有一个清晰的上下文,因为在绘制渐变时所有不透明的东西都会被填充,而不在填充区域的所有东西都会被移除:

 const ctx = createCanvasContext2d( 500, 500 ); document.body.append( ctx.canvas ); const pat = createPattern(); const grad = ctx.createLinearGradient( 0, 0, 500, 500); grad.addColorStop( 0, 'red' ); grad.addColorStop( 0.5, 'yellow' ); grad.addColorStop( 1, 'blue' ); // draw a green rect both in and out of our future gradient pattern ctx.fillStyle = 'green'; ctx.fillRect(0,0,150,150); ctx.arc( 250, 250, 250, 0, Math.PI*2 ); // first the pattern ctx.fillStyle = pat; ctx.fill(); // change the composite operation ctx.globalCompositeOperation = 'source-in'; // now draw the gradient ctx.fillStyle = grad; ctx.fill(); // reset to default ctx.globalCompositeOperation = 'source-over'; function createPattern() { // we create a small canvas context just for the pattern const pattern_ctx = createCanvasContext2d( 20, 20 ); // simply a black circle pattern_ctx.arc( 10, 10, 5, Math.PI*2, 0 ); pattern_ctx.fill(); return pattern_ctx.createPattern( pattern_ctx.canvas, 'repeat' ); } function createCanvasContext2d( width=300, height=width||150 ) { const canvas = document.createElement( 'canvas' ); canvas.width = width; canvas.height = height; return canvas.getContext( '2d' ); }

To avoid this, you can keep a second context that you'll use only to make such compositing operations, and that you'll be able to draw on the main context using drawImage.为避免这种情况,您可以保留第二个上下文,仅用于进行此类合成操作,并且您将能够使用 drawImage 在主上下文上绘图。

 const ctx = createCanvasContext2d( 500, 500 ); document.body.append( ctx.canvas ); const compositing_ctx = createCanvasContext2d( 500, 500 ); const pat = createPattern(); const grad = ctx.createLinearGradient( 0, 0, 500, 500); grad.addColorStop( 0, 'red' ); grad.addColorStop( 0.5, 'yellow' ); grad.addColorStop( 1, 'blue' ); // draw a green rect both in and out of our future gradient pattern ctx.fillStyle = 'green'; ctx.fillRect(0,0,150,150); // make the compositing on the off-screen context compositing_ctx.arc( 250, 250, 250, 0, Math.PI*2 ); compositing_ctx.fillStyle = pat; compositing_ctx.fill(); compositing_ctx.globalCompositeOperation = 'source-in'; compositing_ctx.fillStyle = grad; compositing_ctx.fill(); compositing_ctx.globalCompositeOperation = 'source-over'; // draw to main ctx.drawImage( compositing_ctx.canvas, 0, 0 ); // And a small red one? compositing_ctx.clearRect( 0, 0, 500, 500 ); compositing_ctx.beginPath(); compositing_ctx.rect( 350, 0, 150, 150 ); compositing_ctx.fillStyle = pat; compositing_ctx.fill(); compositing_ctx.globalCompositeOperation = 'source-in'; compositing_ctx.fillStyle = "red"; compositing_ctx.fill(); compositing_ctx.globalCompositeOperation = 'source-over'; // draw to main ctx.drawImage( compositing_ctx.canvas, 0, 0 ); function createPattern() { // we create a small canvas context just for the pattern const pattern_ctx = createCanvasContext2d( 20, 20 ); // simply a black circle pattern_ctx.arc( 10, 10, 5, Math.PI*2, 0 ); pattern_ctx.fill(); return pattern_ctx.createPattern( pattern_ctx.canvas, 'repeat' ); } function createCanvasContext2d( width=300, height=width||150 ) { const canvas = document.createElement( 'canvas' ); canvas.width = width; canvas.height = height; return canvas.getContext( '2d' ); }

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

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