Преобразование <canvas>linearGradient в CSS линейный градиент - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть этот веб-инструмент, который использует HTML Canvas для создания линейных градиентов.Я хочу преобразовать эти градиенты в действительные CSS-градиенты.Я перепробовал все, что я знаю о математике (что не так уж много) ... без реальных результатов.

Вещи, которые я теперь знаю: - Линейный класс CSS может начинаться с отрицательного значения, где градиенты холста не могут.

Вот моя текущая работа:

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 голосов
/ 25 февраля 2019

Как я объяснил в предыдущем ответе , вы можете попробовать использовать 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>

Как видите, мы почти хороши.Расчет позиции немного сложнее и потребует более подробного объяснения.постараюсь отредактировать это позже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...