【问题标题】:Converting <canvas> linearGradient to CSS linear-gradient将 <canvas> 线性渐变转换为 CSS 线性渐变
【发布时间】:2019-02-20 19:59:14
【问题描述】:

我有一个使用 HTML Canvas 创建线性渐变的网络工具。我想将这些渐变转换为有效的 CSS 渐变。我尝试了我所知道的所有数学知识(不是很多)......没有真正的结果。

我现在知道的事情: - CSS 线性渐变可以从负值开始,而 Canvas 渐变不能。

这是我目前的工作:

var width = 50;
var height = 50;

var handlesPositions = [
  {
    "x": 0.16,
    "y": -1.98
  },
  {
    "x": 0.84,
    "y": 2.98
  },
]

var colorStops = [
  {
    "color": "#FF0000",
    "position": 0.359
  },
  {
    "color": "#0094FF",
    "position": 0.495
  },
  {
    "color": "#FFFF00",
    "position": 0.652
  }
];


// CANVAS
var c = document.getElementById("source");
var ctx = c.getContext("2d");

var x0 = handlesPositions[0].x * width;
var y0 = handlesPositions[0].y * height;
var x1 = handlesPositions[1].x * width;
var y1 = handlesPositions[1].y * height;

var grd = ctx.createLinearGradient(x0, y0, x1, y1);

grd.addColorStop(colorStops[0].position, colorStops[0].color);
grd.addColorStop(colorStops[1].position, colorStops[1].color);
grd.addColorStop(colorStops[2].position, colorStops[2].color);

ctx.fillStyle = grd;
ctx.fillRect(0, 0, 50, 50);


// CANVAS TO CSS
function canvasToLinearGradient(handles, stops) {
  const handle0 = handles[0];
  const handle1 = handles[1];

  const ydiff = handle1.y - handle0.y;
  const xdiff = handle0.x - handle1.x;

  const angle = Math.atan2(-xdiff, -ydiff);
  const cssStops = stops.map((stop) => {
    return `${stop.color} ${Math.round(stop.position * 100)}%`;
  }).join(', ');
  return `linear-gradient(${angle}rad, ${cssStops})`;
}


document.getElementById("current").style.backgroundImage = canvasToLinearGradient(handlesPositions, colorStops);
#goal {
background: linear-gradient(172.19deg, #FF0000 -12.39%, #0094FF 48.06%, #FFFF00 117.89%);
}

.row {
  display: flex;flex-direction:row;justify-content:space-between;align-items:center;margin-bottom:10px
}
<div style="width: 230px">
  <div class="row">Goal <div id="goal" style="width:50px;height:50px;"></div></div>
  <div class="row">Source <canvas id="source" width="50" height="50"></canvas></div>
  <div class="row">Current result <div id="current" style="width:50px;height:50px;"></div>
</div>

【问题讨论】:

  • 这可能对你有帮助:stackoverflow.com/a/51884567/8620333 .. 你会在那里找到一些数学。检查您不必使用背景大小的第二部分
  • @TemaniAfif 无法正常工作。 :(
  • 好的很快就会添加答案

标签: javascript html css html5-canvas linear-gradients


【解决方案1】:

正如我在previous answer 中解释的那样,您可以尝试依靠background-size/background-position 来创建渐变。

首先,您可以在这里转换第一个渐变以使颜色介于 0%100% 之间,并在以后使用 Canvas 轻松处理

#goal {
  background: linear-gradient(172.19deg, #FF0000 -12.39%, #0094FF 48.06%, #FFFF00 117.89%);
}

#goal-1 {
  /*we add 12.39% to all to make the first one 0%*/
  background: linear-gradient(172.19deg, #FF0000 0%, #0094FF 60.45%, #FFFF00 130.29%);
}

#goal-2 {
  /*we divide by 1.3029 all to make the last one 100%*/
  background: linear-gradient(172.19deg, #FF0000 0%, #0094FF 46.39%, #FFFF00 100%);
}
#goal-3 {
  /*we increase the size by 1.3029 to rectify the previous division*/
  background: linear-gradient(172.19deg, #FF0000 0%, #0094FF 46.39%, #FFFF00 100%);
  background-size:130.29% 130.29%;
}
#goal-4 {
  /*we move the gradient to rectify the -12.39%*/
  background: linear-gradient(172.19deg, #FF0000 0%, #0094FF 46.39%, #FFFF00 100%);
  background-size:130.29% 130.29%;
  background-position:calc((-0.1239 * 50px)/1.3029) calc((-0.1239 * 50px)/1.3029)
}
#goal-5 {
  /*we can also wrote*/
  background: linear-gradient(172.19deg, #FF0000 0%, #0094FF 46.39%, #FFFF00 100%) calc((-0.1239 * 50px)/1.3029) calc((-0.1239 * 50px)/1.3029)/ 130.29% 130.29%;}


.row {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px
}
<div style="width: 230px">
  <div class="row">Goal
    <div id="goal" style="width:50px;height:50px;"></div>
  </div>
  <div class="row">Transition 1
    <div id="goal-1" style="width:50px;height:50px;"></div>
  </div>
  <div class="row">Transition 2
    <div id="goal-2" style="width:50px;height:50px;"></div>
  </div>
  <div class="row">Transition 3
    <div id="goal-3" style="width:50px;height:50px;"></div>
  </div>
  <div class="row">Transition final
    <div id="goal-4" style="width:50px;height:50px;"></div>
  </div>
  <div class="row">Transition final
    <div id="goal-5" style="width:50px;height:50px;"></div>
  </div>
</div>

现在我们可以应用这个逻辑来找到我们的渐变。我们已经有了色标。现在我们需要正确找到梯度的大小,即两点之间的距离。然后找到背景位置。

这是我添加背景大小的第一次尝试:

var width = 50;
var height = 50;

var handlesPositions = [
  {
    "x": 0.16,
    "y": -1.98
  },
  {
    "x": 0.84,
    "y": 2.98
  },
]

var colorStops = [
  {
    "color": "#FF0000",
    "position": 0.359
  },
  {
    "color": "#0094FF",
    "position": 0.495
  },
  {
    "color": "#FFFF00",
    "position": 0.652
  }
];


// CANVAS
var c = document.getElementById("source");
var ctx = c.getContext("2d");

var x0 = handlesPositions[0].x * width;
var y0 = handlesPositions[0].y * height;
var x1 = handlesPositions[1].x * width;
var y1 = handlesPositions[1].y * height;

var grd = ctx.createLinearGradient(x0, y0, x1, y1);

grd.addColorStop(colorStops[0].position, colorStops[0].color);
grd.addColorStop(colorStops[1].position, colorStops[1].color);
grd.addColorStop(colorStops[2].position, colorStops[2].color);

ctx.fillStyle = grd;
ctx.fillRect(0, 0, 50, 50);


// CANVAS TO CSS
function canvasToLinearGradient(handles, stops) {
  const handle0 = handles[0];
  const handle1 = handles[1];

  const ydiff = handle1.y - handle0.y;
  const xdiff = handle0.x - handle1.x;

  const angle = Math.atan2(-xdiff, -ydiff);
  const dist= Math.sqrt((y1-y0)*(y1-y0) + (x1-x0)*(x1-x0));
  console.log(dist);
  
  const cssStops = stops.map((stop) => {
    return `${stop.color} ${stop.position * 100}%`;
  }).join(', ');
  return `linear-gradient(${angle}rad, ${cssStops}) 50% 50%/${dist}px ${dist}px`;
}


document.getElementById("current").style.background = canvasToLinearGradient(handlesPositions, colorStops);
#goal {
background: linear-gradient(172.19deg, #FF0000 -12.39%, #0094FF 48.06%, #FFFF00 117.89%);
}

.row {
  display: flex;flex-direction:row;justify-content:space-between;align-items:center;margin-bottom:10px
}
<div style="width: 230px">
  <div class="row">Goal <div id="goal" style="width:50px;height:50px;"></div></div>
  <div class="row">Source <canvas id="source" width="50" height="50"></canvas></div>
  <div class="row">Current result <div id="current" style="width:50px;height:50px;"></div>
</div>

如您所见,我们几乎可以做到。位置的计算有点棘手,需要更深入的解释。稍后将尝试编辑此内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 2021-12-28
    • 1970-01-01
    • 2021-11-24
    • 2019-06-30
    • 1970-01-01
    相关资源
    最近更新 更多