[英]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.