M.E*_*vin 5 css opacity linear-gradients rgba html5-canvas
我想在画布上实现由 CSS 定义的相同线性渐变外观。使用了一种在不使用透明度设置之前效果很好的方法。当使用相同的线性渐变颜色设置定义了 rgba 颜色值时,结果看起来不一样,请参阅以下链接:
JSFiddle: 例子
var canvas = document.getElementById("myCanvas");
var ctx = document.getElementById("myCanvas").getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cssAng = Math.PI;
var dir = getDir(cssAng, w, h);
var gr = ctx.createLinearGradient(dir.x0,dir.y0,dir.x1,dir.y1);
gr.addColorStop(0, "rgb(255, 255, 255, 0)");
gr.addColorStop(0.87, "rgb(0, 0, 0, 1)");
ctx.fillStyle = gr;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
function getDir(radian, width, height) {
radian += Math.PI;
const HALF_WIDTH = width * 0.5;
const HALF_HEIGHT = height * 0.5;
const lineLength = Math.abs(width * Math.sin(radian)) + Math.abs(height * Math.cos(radian));
const HALF_LINE_LENGTH = lineLength / 2;
const x0 = HALF_WIDTH + Math.sin(radian) * HALF_LINE_LENGTH;
const y0 = HALF_HEIGHT - Math.cos(radian) * HALF_LINE_LENGTH;
const x1 = width - x0;
const y1 = height - y0;
return {x0, x1, y0, y1};
}Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<body>
<div style='background-color:gray;display:inline-block;max-height:300px'>
<div id="myDiv" style="display:inline-block;width:300px;height:300px;border:1px solid #d3d3d3;background:linear-gradient(180deg,rgba(255,255,255, 0) 0%, rgba(0,0,0,1) 87%"> </div>
</div>
<canvas id="myCanvas" width="300" height="300" style="background-color: gray;border:1px solid #d3d3d3;"> </canvas>
</body>
</html>Run Code Online (Sandbox Code Playgroud)
知道为什么会这样吗?有没有可以处理这个问题的包?
CSS linear-gradient和canvas linear gradient的规格实际上是有区别的。除了需要根据 alpha 值计算颜色的方式外,它们看起来几乎完全相同。对于 CSS 线性渐变,你有这个:
3.4.2. 给渐变线着色 在每个色标位置,渐变线就是色标的颜色。在第一个色标之前,渐变线是第一个色标的颜色,在最后一个色标之后,渐变线是最后一个色标的颜色。在两个色标之间,渐变线的颜色在两个色标的颜色之间进行插值,插值发生在预乘 RGBA 空间中。
请参阅:https : //drafts.csswg.org/css-images-3/#coloring-gradient-line
而画布一:
创建渐变后(见下文),沿其放置停靠点以定义颜色如何沿渐变分布。每个停靠点的渐变颜色是为该停靠点指定的颜色。在每个这样的停止点之间,颜色和 alpha 分量必须在 RGBA 空间上线性插值,而无需预先乘以 alpha 值来找到要在该偏移处使用的颜色。在第一站之前,颜色必须是第一站的颜色。
请参阅:https : //html.spec.whatwg.org/multipage/canvas.html#interpolation
所以 CSS 版本通过预乘它们的 alpha 值来计算色标。我已经改变了你的例子,让它更明显一点。在下面的示例中,CSS 版本从rgba(255, 0, 0, 0)或rgba(0, 0, 0, 0)变为rgba(0, 0, 0, 1)。因此,在 50% 时,使用预乘 alpha 计算的颜色为rgba(0, 0, 0, 0.5)。
在画布版本中,插值是在没有预乘的情况下计算的。所以在 50% 你有rgba(127,5, 0, 0, 0.5)。对于梯度线的每个点都是如此。
请参阅预乘意味着什么:https : //drafts.csswg.org/css-images-3/#premultiplied
和例子:
var canvas = document.getElementById("myCanvas");
var ctx = document.getElementById("myCanvas").getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cssAng = Math.PI;
var dir = getDir(cssAng, w, h);
var gr = ctx.createLinearGradient(dir.x0,dir.y0,dir.x1,dir.y1);
gr.addColorStop(0, "rgb(255, 0, 0, 0)");
gr.addColorStop(1, "rgb(0, 0, 0, 1)");
ctx.fillStyle = gr;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
function getDir(radian, width, height) {
radian += Math.PI;
const HALF_WIDTH = width * 0.5;
const HALF_HEIGHT = height * 0.5;
const lineLength = Math.abs(width * Math.sin(radian)) + Math.abs(height * Math.cos(radian));
const HALF_LINE_LENGTH = lineLength / 2;
const x0 = HALF_WIDTH + Math.sin(radian) * HALF_LINE_LENGTH;
const y0 = HALF_HEIGHT - Math.cos(radian) * HALF_LINE_LENGTH;
const x1 = width - x0;
const y1 = height - y0;
return {x0, x1, y0, y1};
}Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<body>
<div style='display:inline-block;max-height:300px'>
<div id="myDiv" style="display:inline-block;width:200px;height:300px;border:1px ;background:linear-gradient(180deg,rgba(255,0,0, 0) 0%, rgba(0,0,0,1) 100%"> </div>
</div>
<canvas id="myCanvas" width="200" height="300" > </canvas>
<div style="position: absolute;width:8px;height:8px;background:rgba(0,0,0,0.5); top: 144px; left: 0px; ">
</div>
<div style="position: absolute;width:10px;height:10px;background:rgba(127.5,0,0,0.5); top: 144px; left: 412px; ">
</div>
</body>
</html>Run Code Online (Sandbox Code Playgroud)
我认为没有办法使 2 等效,除非计算渐变线的每个点。
小智 -1
不能说这是否是解决您问题的正确方法,但这是一种解决方法。在中间添加一个图层并调整黑色、灰色和白色部分的比例。它们完全不同,我想添加更多的颜色停止点以更好地控制颜色的放置。
var canvas = document.getElementById("myCanvas");
var ctx = document.getElementById("myCanvas").getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cssAng = Math.PI;
var dir = getDir(cssAng, w, h);
var gr = ctx.createLinearGradient(dir.x0,dir.y0,dir.x1,dir.y1);
gr.addColorStop(0, "rgb(255,255,255)");
gr.addColorStop(0, "rgb(125,125,125)");
gr.addColorStop(.9, "rgb(0,0,0)" );
ctx.fillStyle = gr;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
function getDir(radian, width, height) {
radian += Math.PI;
const HALF_WIDTH = width * 0.5;
const HALF_HEIGHT = height * 0.5;
const lineLength = Math.abs(width * Math.sin(radian)) + Math.abs(height * Math.cos(radian));
const HALF_LINE_LENGTH = lineLength / 2;
const x0 = HALF_WIDTH + Math.sin(radian) * HALF_LINE_LENGTH;
const y0 = HALF_HEIGHT - Math.cos(radian) * HALF_LINE_LENGTH;
const x1 = width - x0;
const y1 = height - y0;
return {x0, x1, y0, y1};
}Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<body>
<div style='background-color:gray;display:inline-block;max-height:300px'>
<div id="myDiv" style="display:inline-block;width:300px;height:300px;border:1px solid #d3d3d3;background:linear-gradient(180deg,rgba(255,255,255, 0) 0%, rgba(0,0,0,1) 87%"> </div>
</div>
<canvas id="myCanvas" width="300" height="300" style="background-size: cover;background-color: gray;border:1px solid #d3d3d3;"> </canvas>
</body>
</html>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
382 次 |
| 最近记录: |