[英]Canvas linear gradient taking the value of another input type color field
So I have this simple image editor where I'm using a canvas to draw in a user-selected image and some texts.所以我有这个简单的图像编辑器,我使用 canvas 来绘制用户选择的图像和一些文本。 That is the user can upload an image and then if they want they can add texts or just change the gradient of the image.
也就是说,用户可以上传图像,然后如果他们愿意,他们可以添加文本或只是更改图像的渐变。
Right now the app works perfectly fine except there is one issue.现在该应用程序运行良好,除了有一个问题。
How to find the issue?如何找到问题? Do the following:
请执行下列操作:
Text 2 Shadow Offset X
Color Picker.Text 2 Shadow Offset X
Color Picker 中选择一种颜色。Text 2 Shadow Offset X
Color Picker.Text 2 Shadow Offset X
Color Picker旁边增加slider。Image Gradient and Opacity
.Image Gradient and Opacity
的 slider 。 The image will have a gradient and take the value of the Text 2 Shadow Offset X
Color Picker instead of Image Gradient and Opacity
Color Picker which has default black color.图像将具有渐变并采用
Text 2 Shadow Offset X
Color Picker 的值,而不是具有默认黑色的Image Gradient and Opacity
Color Picker 的值。
This is the code:这是代码:
const canvasTxt = window.canvasTxt.default; const canvas = document.getElementById('canvas'); const ctx = canvas?.getContext('2d'); const btnDownload = document.querySelector('.btnDownload'); const fileUpload = document.querySelector('.file-upload'); const text1 = document.getElementById('text1'); const textForm1 = document.getElementById('text1-form'); const text2 = document.getElementById('text2'); const textForm2 = document.getElementById('text2-form'); const text2ShadowColor = document.getElementById('text2shadowcolor'); const text2ShadowOffsetY = document.getElementById('text2shadowoffy'); const imageForm = document.getElementById('image-form'); const imageGrad = document.getElementById('gradientcolor'); const imageGradOpacity = document.getElementById('gradientopacity'); $(fileUpload).on('change', function(e) { let imgObj = new Image(); imgObj.onload = draw; imgObj.onerror = failed; imgObj.src = URL.createObjectURL(this.files[0]); imgManipulation( e, imgObj ); }); const imgManipulation = ( e, imgObj ) => { $(textForm1).on('change keyup input', updateCanvas); $(textForm2).on('change keyup input', updateCanvas); $(imageForm).on('change keyup input', updateCanvas); function updateCanvas(e) { e.preventDefault(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(imgObj, 0, 0); createGradient($(imageGrad).val(), $(imageGradOpacity).val()); // TEXT1 STYLES based on user input canvasTxt.fontSize = 30; canvasTxt.drawText( ctx, $(text1).val(), 0, 0, 200, 200 ); // TEXT2 STYLES canvasTxt.font = 20; canvasTxt.drawText( ctx, $(text2).val(), 20, 20, 200, 200 ); } }; function hexToRgb(hex) { var result = /^#?([af\d]{2})([af\d]{2})([af\d]{2})$/i.exec(hex); return result? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }: null; }; function createGradient(hex, alpha) { const r = hexToRgb(hex).r.toString(); const g = hexToRgb(hex).g.toString(); const b = hexToRgb(hex).b.toString(); var gradient = ctx.createLinearGradient(800, 0, 0, 0); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${alpha})`); ctx.save() // <----------- ADD ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore() // <----------- ADD }; function draw() { canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; const nw = this.naturalWidth; const nh = this.naturalHeight; ctx.drawImage(this, 0, 0, nw, nh); }; function failed() { console.error("The provided file couldn't be loaded as an Image media"); }; $(btnDownload).on('click', function(e) { const a = document.createElement('a'); document.body.appendChild(a); a.href = canvas.toDataURL(); a.download = "canvas-image.png"; a.click(); document.body.removeChild(a); });
#canvas{ background-color: transparent; width: 30%; height: auto; border: 1px solid #777; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/canvas-txt@3.0.0/build/index.js"></script> <canvas id="canvas" width="800" height="500"></canvas> <div> <input type="file" class="file-upload" /> <button class="btnDownload">Download</button> </div> <div> <form id="text1-form"> <input type="text" id="text1" placeholder="text 1"/> </form> </div> <div> <form id="text2-form"> <input type="text" id="text2" placeholder="text 2"/> </form> </div> <div> <h2>Image Gradient and Opacity</h2> <form id="image-form"> <input type="color" id="gradientcolor" value="#000000" /> <input type="range" id="gradientopacity" min="0" max="1" value="0" step="0.05" /> </form> </div> <div> <h2>Text2 Shadow Offset X</h2> <input type="color" id="text2shadowcolor" value="#000000" /> <input type="range" id="text2shadowoffy" min="0" max="40" value="0" /> </div>
Rundown of the code:代码概要:
1: First I have the fileUpload
event listener. 1:首先我有
fileUpload
事件监听器。 It takes in an image from the user and creates an image object and draws it on the canvas.它从用户那里获取图像并创建图像 object 并将其绘制在 canvas 上。 Then
imgManipulation
function is called with the imgObj
and event
as its arguments.然后
imgManipulation
function 并使用imgObj
和event
作为其 arguments。
The imgManipulation
function starts off with the input
event listeners for the texts. imgManipulation
function 从文本的input
事件侦听器开始。 That is whenever there is a change in the input, that is a user writes something, updateCanvas
function is called.也就是说,只要输入发生变化,即用户写了一些东西,就会调用
updateCanvas
function。
The updateCanvas
function actually draws the texts on the image. updateCanvas
function 实际上是在图像上绘制文本。 I'm using a package called canvasTxt
which helps the text to be multiline.我正在使用名为
canvasTxt
的 package 来帮助文本成为多行。
The createGradient
function call inside updateCanvas
is the image gradient for the image. updateCanvas
内部的createGradient
function 调用是图像的图像渐变。
I tried moving the createGradient function call below the drawTexts but then the gradient comes to the top of everything.我尝试将 createGradient function 调用移动到 drawTexts 下方,但随后渐变出现在所有内容的顶部。 The texts become darker too.
文字也变暗了。
How can I make the gradient take it's value only instead of shadow color?如何使渐变仅取其值而不是阴影颜色?
Your help would be highly appreciated.您的帮助将不胜感激。
Thanks in advance提前致谢
This is because since you didn't reset the shadow options, the gradient itself is affected by the shadowing, just like it would be affected by a filter if it makes things clearer to you:这是因为由于您没有重置阴影选项,渐变本身会受到阴影的影响,就像它会受到过滤器的影响一样,如果它让您更清楚的话:
const ctx = canvas.getContext( "2d" ); // a vertical green to transparent gradient const grad = ctx.fillStyle = ctx.createLinearGradient( 0, 0, 0, 150 ); grad.addColorStop( 0, "rgba(0,255,0)" ); grad.addColorStop( 1, "rgba(0,255,0,0.01)" ); ctx.textAlign = "center"; ctx.fillRect( 0, 0, 50, 150 ); ctx.filter = "sepia(1)"; ctx.fillRect( 75, 0, 50, 150 ); ctx.filter = "invert(1)"; ctx.fillRect( 150, 0, 50, 150 ); ctx.filter = "none"; // disable filtering ctx.shadowColor = "red"; ctx.shadowOffsetX = 15; ctx.shadowOffsetY = 25; ctx.fillRect( 225, 0, 50, 150 ); // disable shadows ctx.shadowColor = "transparent"; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.fillStyle = "black"; ctx.fillText( "sepia(1)", 100, 20 ); ctx.fillText( "none", 25, 20 ); ctx.fillText( "invert(1)", 175, 20 ); ctx.fillText( "shadow", 250, 20 );
<canvas id="canvas" width="500"></canvas>
As you can see, because your gradient is not fully opaque, the shadow is visible behind it, and the rendered color is altered.正如你所看到的,因为你的渐变不是完全不透明的,阴影在它后面是可见的,并且渲染的颜色被改变了。
To workaround that, you can simply do as I did in my example:要解决此问题,您可以像我在示例中所做的那样简单地做:
// disable shadows
ctx.shadowColor = "transparent";
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
const canvasTxt = window.canvasTxt.default; const canvas = document.getElementById('canvas'); const ctx = canvas?.getContext('2d'); const btnDownload = document.querySelector('.btnDownload'); const fileUpload = document.querySelector('.file-upload'); const text1 = document.getElementById('text1'); const textForm1 = document.getElementById('text1-form'); const text2 = document.getElementById('text2'); const textForm2 = document.getElementById('text2-form'); const text2ShadowColor = document.getElementById('text2shadowcolor'); const text2ShadowOffsetY = document.getElementById('text2shadowoffy'); const imageForm = document.getElementById('image-form'); const imageGrad = document.getElementById('gradientcolor'); const imageGradOpacity = document.getElementById('gradientopacity'); $(fileUpload).on('change', function(e) { let imgObj = new Image(); imgObj.onload = draw; imgObj.onerror = failed; imgObj.src = URL.createObjectURL(this.files[0]); imgManipulation( e, imgObj ); }); const imgManipulation = ( e, imgObj ) => { $(textForm1).on('change keyup input', updateCanvas); $(textForm2).on('change keyup input', updateCanvas); $(imageForm).on('change keyup input', updateCanvas); function updateCanvas() { e.preventDefault(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(imgObj, 0, 0); createGradient($(imageGrad).val(), $(imageGradOpacity).val()); // TEXT1 STYLES based on user input canvasTxt.fontSize = 30; canvasTxt.drawText( ctx, $(text1).val(), 0, 0, 0, 0 ); // TEXT2 STYLES ctx.shadowColor = $(text2ShadowColor).val(); ctx.shadowOffsetY = $(text2ShadowOffsetY).val(); canvasTxt.font = 20; canvasTxt.drawText( ctx, $(text2).val(), 20, 20, 0, 0 ); // clean behind ctx.shadowColor = "transparent"; ctx.shadowOffsetY = 0; } }; function hexToRgb(hex) { var result = /^#?([af\d]{2})([af\d]{2})([af\d]{2})$/i.exec(hex); return result? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }: null; }; function createGradient(hex, alpha) { const r = hexToRgb(hex).r.toString(); const g = hexToRgb(hex).g.toString(); const b = hexToRgb(hex).b.toString(); var gradient = ctx.createLinearGradient(800, 0, 0, 0); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${alpha})`); const current_fill_style = ctx.fillStyle; ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); // clean behind ctx.fillStyle = current_fill_style; }; function draw() { canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; const nw = this.naturalWidth; const nh = this.naturalHeight; ctx.drawImage(this, 0, 0, nw, nh); }; function failed() { console.error("The provided file couldn't be loaded as an Image media"); }; $(btnDownload).on('click', function(e) { const a = document.createElement('a'); document.body.appendChild(a); a.href = canvas.toDataURL(); a.download = "canvas-image.png"; a.click(); document.body.removeChild(a); });
#canvas{ background-color: transparent; width: 30%; height: auto; border: 1px solid #777; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/canvas-txt@3.0.0/build/index.js"></script> <canvas id="canvas" width="800" height="500"></canvas> <div> <input type="file" class="file-upload" /> <button class="btnDownload">Download</button> </div> <div> <form id="text1-form"> <input type="text" id="text1" placeholder="text 1"/> </form> </div> <div> <form id="text2-form"> <input type="text" id="text2" placeholder="text 2"/> </form> </div> <div> <h2>Image Gradient and Opacity</h2> <form id="image-form"> <input type="color" id="gradientcolor" value="#000000" /> <input type="range" id="gradientopacity" min="0" max="1" value="0" step="0.05" /> </form> </div> <div> <h2>Text2 Shadow Offset X</h2> <input type="color" id="text2shadowcolor" value="#000000" /> <input type="range" id="text2shadowoffy" min="0" max="40" value="0" /> </div>
The shadowColor
still work when drawing 'Gradient' next time.下次绘制“渐变”时,
shadowColor
仍然有效。 Add ctx.save()
before, and ctx.restore()
after.在之前添加
ctx.save()
,在之后添加 ctx.restore( ctx.restore()
。
const canvasTxt = window.canvasTxt.default; const canvas = document.getElementById('canvas'); const ctx = canvas?.getContext('2d'); const btnDownload = document.querySelector('.btnDownload'); const fileUpload = document.querySelector('.file-upload'); const text1 = document.getElementById('text1'); const textForm1 = document.getElementById('text1-form'); const text2 = document.getElementById('text2'); const textForm2 = document.getElementById('text2-form'); const text2ShadowColor = document.getElementById('text2shadowcolor'); const text2ShadowOffsetY = document.getElementById('text2shadowoffy'); const imageForm = document.getElementById('image-form'); const imageGrad = document.getElementById('gradientcolor'); const imageGradOpacity = document.getElementById('gradientopacity'); $(fileUpload).on('change', function(e) { let imgObj = new Image(); imgObj.onload = draw; imgObj.onerror = failed; imgObj.src = URL.createObjectURL(this.files[0]); imgManipulation( e, imgObj ); }); const imgManipulation = ( e, imgObj ) => { $(textForm1).on('change keyup input', updateCanvas); $(textForm2).on('change keyup input', updateCanvas); $(imageForm).on('change keyup input', updateCanvas); function updateCanvas() { e.preventDefault(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(imgObj, 0, 0); createGradient($(imageGrad).val(), $(imageGradOpacity).val()); // TEXT1 STYLES based on user input canvasTxt.fontSize = 30; canvasTxt.drawText( ctx, $(text1).val(), 0, 0, 0, 0 ); // TEXT2 STYLES ctx.save() // <----------- ADD ctx.shadowColor = $(text2ShadowColor).val(); ctx.shadowOffsetY = $(text2ShadowOffsetY).val(); canvasTxt.font = 20; canvasTxt.drawText( ctx, $(text2).val(), 20, 20, 0, 0 ); ctx.restore() // <----------- ADD } }; function hexToRgb(hex) { var result = /^#?([af\d]{2})([af\d]{2})([af\d]{2})$/i.exec(hex); return result? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }: null; }; function createGradient(hex, alpha) { const r = hexToRgb(hex).r.toString(); const g = hexToRgb(hex).g.toString(); const b = hexToRgb(hex).b.toString(); var gradient = ctx.createLinearGradient(800, 0, 0, 0); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${alpha})`); ctx.save() // <----------- ADD ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore() // <----------- ADD }; function draw() { canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; const nw = this.naturalWidth; const nh = this.naturalHeight; ctx.drawImage(this, 0, 0, nw, nh); }; function failed() { console.error("The provided file couldn't be loaded as an Image media"); }; $(btnDownload).on('click', function(e) { const a = document.createElement('a'); document.body.appendChild(a); a.href = canvas.toDataURL(); a.download = "canvas-image.png"; a.click(); document.body.removeChild(a); });
#canvas{ background-color: transparent; width: 30%; height: auto; border: 1px solid #777; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/canvas-txt@3.0.0/build/index.js"></script> <canvas id="canvas" width="800" height="500"></canvas> <div> <input type="file" class="file-upload" /> <button class="btnDownload">Download</button> </div> <div> <form id="text1-form"> <input type="text" id="text1" placeholder="text 1"/> </form> </div> <div> <form id="text2-form"> <input type="text" id="text2" placeholder="text 2"/> </form> </div> <div> <h2>Image Gradient and Opacity</h2> <form id="image-form"> <input type="color" id="gradientcolor" value="#000000" /> <input type="range" id="gradientopacity" min="0" max="1" value="0" step="0.05" /> </form> </div> <div> <h2>Text2 Shadow Offset X</h2> <input type="color" id="text2shadowcolor" value="#000000" /> <input type="range" id="text2shadowoffy" min="0" max="40" value="0" /> </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.