将<canvas> linearGradient转换为CSS linear-gradient

时间:2019-02-20 19:59:15

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

我有这个使用HTML Canvas创建线性渐变的Web工具。我想将这些渐变转换为有效的CSS渐变。我尝试了我所知道的关于数学的一切(不是很多)……没有任何实际结果。

我现在知道的事情: -CSS线性gradeint可以从负值开始,而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>

1 个答案:

答案 0 :(得分: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>

如您所见,我们几乎很好。位置的计算有些棘手,将需要更多的深度说明。稍后将尝试对其进行编辑。