Реализация HTML5-градиентов холста в React - PullRequest
0 голосов
/ 05 марта 2019

Я пытаюсь создать приложение, которое позволяет создавать градиент фона с двумя разными цветами, я использую React.Первый цвет градиента выглядит так, как должен, но второй цвет градиента более сплошной, с зазубренной границей.Вот картинка для демонстрации: enter image description here

Моя цель - получить что-то, что ближе к этому: enter image description here

Гдецвета смешиваются.

Я имею в виду документы MDN , и мне не хватает свойств радиуса и x, y.Я изменяю холст на основе изменений реквизита родительского компонента, вот мой код:

import React, { Component } from "react";

class Canvas extends Component {
  componentDidMount() {
    const { gradientOne, gradientTwo } = this.props.canvasState.backgroundColor;
    this.ctx = this.canvas.getContext("2d");
    this.radialGradient = this.ctx.createRadialGradient(
      0,
      0,
      300,
      260,
      160,
      100
    );

    this.ctx.fillStyle = this.radialGradient;
    this.ctx.rect(0, 0, this.canvas.width, this.canvas.height);
    this.radialGradient.addColorStop(0, gradientOne);
    this.radialGradient.addColorStop(1, gradientTwo);
    this.ctx.fill();
  }

  componentDidUpdate(prevProps, prevState) {
    const { gradientOne, gradientTwo } = this.props.canvasState.backgroundColor;
    if (prevProps.canvasState.backgroundColor.gradientOne !== gradientOne) {
      this.ctx.fillStyle = this.radialGradient;
      this.radialGradient.addColorStop(0, gradientOne);
      this.ctx.fill();
    } else if (
      prevProps.canvasState.backgroundColor.gradientTwo !== gradientTwo
    ) {
      this.ctx.fillStyle = this.radialGradient;
      this.radialGradient.addColorStop(1, gradientTwo);
      this.ctx.fill();
    }
  }
  render() {
    return (
      <main className="canvasContainer">
        <canvas ref={ref => (this.canvas = ref)} id="canvas">
          YOUR BROWSER DOESN'T SUPPORT THIS FEATURE :(
        </canvas>
      </main>
    );
  }
}

export default Canvas;

Спасибо за любую помощь!

1 Ответ

1 голос
/ 06 марта 2019

Цветовые остановки CanvasGradient (линейные или радиальные) не могут быть изменены или удалены.
Когда вы добавляете новый ограничитель цвета с тем же индексом, что и предыдущий, он размещается сразу после предыдущего. Таким образом, вместо двух цветовых остановок у вас есть четыре.

Это означает, что если у вас есть оригинальный градиент, как это

 <-red -------------------------------------------- green->

и что вы добавите две новые цветовые остановки blue и yellow в позиции 0 и 1, у вас будет что-то вроде

 <-red[blue -------------------------------- green]yellow->

То есть, нет градиента ни между красным и синим, ни между желтым и зеленым:

const ctx = canvas.getContext('2d');
ctx.strokeStyle = 'white';
// an horizontal gradient
// 0 is at pixel 50, and 1 at pixel 250 on the x axis
const grad = ctx.createLinearGradient(50,0,250,0);
grad.addColorStop(0, 'red');
grad.addColorStop(1, 'green');
ctx.fillStyle = grad;
// top is two color stops version
ctx.fillRect(0,0,300,70);

// bottom is four color stops version
grad.addColorStop(0, 'blue');
grad.addColorStop(1, 'yellow');
ctx.fillStyle = grad;
ctx.fillRect(0,80,300,70);

//  mark color stops
ctx.moveTo(49.5,0);
ctx.lineTo(49.5,150);
ctx.moveTo(249.5,0);
ctx.lineTo(249.5,150);
ctx.stroke();
canvas { border: 1px solid };
<canvas id="canvas"></canvas>

Это то, что вы делаете в своем коде, поскольку вы добавляете две цветовые остановки в componentDidMount, а затем добавляете больше в componentDidUpdate.

Чтобы избежать этого, просто перезапишите свойство gradient в componentDidUpdate, чтобы каждый раз начинать с нового градиента.

const ctx = canvas.getContext('2d');
let radialGradient;
function didMount() {
  radialGradient = ctx.createRadialGradient(
    0,0,300,
    260,160,100
   );
  radialGradient.addColorStop(0, c1.value);
  radialGradient.addColorStop(1, c2.value);
  ctx.fillStyle = radialGradient;
  ctx.fillRect(0,0,canvas.width,canvas.height);
}
function didUpdate() {
  // reset radialGradient to a new one
  radialGradient = ctx.createRadialGradient(
    0,0,300,
    260,160,100
   );
  radialGradient.addColorStop(0, c1.value);
  radialGradient.addColorStop(1, c2.value);
  ctx.fillStyle = radialGradient;
  ctx.fillRect(0,0,canvas.width,canvas.height);
}

didMount();
c1.oninput = c2.oninput = didUpdate;
canvas { border: 1px solid };
<input id="c1" type="color" value="#22CC22">
<input id="c2" type="color" value="#FF2222">
<canvas id="canvas"></canvas>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...