Создание динамического c холста фона для div с помощью React - PullRequest
0 голосов
/ 25 апреля 2020

Я хочу создать динамический c фон для указанного c компонента на моем веб-сайте с помощью React. Я хочу сделать так, чтобы этот фон представлял собой холст, на котором выполняется моделирование реагирующих частиц js. Все находится внутри компонента React и, как обычно, отображается методом render(). Результат должен выглядеть следующим образом:

something like this

Код компонента, имеющего фон, должен выглядеть примерно так:

class ParticleBackgrondComponent extends Component{

render(){
    return (

        <div>
            <Particles/> {//The particle background}

            <h3>
                Some other content
            </h3>
            <p>
                Lorem ipsum dolor sit amet...
            </p>

        </div>
    )
}

}

Я попытался установить абсолютное положение указанного холста и вручную поместить его позади желаемого div, но он не работает, когда я изменяю размер окна.

Ответы [ 3 ]

0 голосов
/ 25 апреля 2020

Пока element() не поддерживается, вы можете полностью расположить фоновый элемент за элементом переднего плана и динамически установить ширину и высоту холста в зависимости от размера переднего плана:

const TAU = 2 * Math.PI;

class Circle {
  constructor(canvas) {
    this.x = Math.random() * canvas.width;
    this.y = Math.random() * canvas.height;
    this.r = Math.random() * Math.sqrt(canvas.width ** 2 + canvas.height ** 2) / 8;
    this.growth = Math.random() * 4;
    this.decay = Math.max(Math.random() * 0.005, 0.0005);
    this.rgb = [
      Math.random() * 255,
      Math.random() * 255,
      Math.random() * 255,
    ];
    this.alpha = Math.random() * 0.35;
  }
  
  get fillStyle() {
    return `rgba(${this.rgb.join(',')},${this.alpha})`;
  }
  
  render(ctx) {
    ctx.beginPath();
    ctx.fillStyle = this.fillStyle;
    ctx.arc(this.x, this.y, this.r, 0, TAU);
    ctx.fill();
    
    this.r += this.growth;
    this.alpha -= this.decay;
  }
}

function render(ctx, foreground, circles = []) {
  const { width, height } = foreground.getBoundingClientRect();
  ctx.canvas.width = width;
  ctx.canvas.height = height;

  ctx.clearRect(0, 0, width, height);
  
  if (circles.length === 0) {
    circles.push(new Circle(ctx.canvas));
  }
  
  if (Math.random() > 0.98) {
    circles.push(new Circle(ctx.canvas));
  }
  
  for (const circle of circles) {
    circle.render(ctx);
  }
  
  window.requestAnimationFrame(() => {
    render(ctx, foreground, circles.filter(circle => circle.alpha > 0))
  });
}

window.addEventListener("DOMContentLoaded", () => {
  const canvas = document.querySelector("canvas");
  const foreground = document.querySelector(".foreground");

  render(canvas.getContext("2d"), foreground);
});
.container {
  position: relative;
}

.background {
  position: absolute;
  z-index: -1;
}
<div class="container">
  <canvas class="background"></canvas>
  <div class="foreground">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur placerat quam a vulputate tincidunt. Aliquam pretium leo quis justo pretium, in pellentesque augue viverra.</p>
    <p>Quisque lacinia ipsum id purus varius molestie. Integer tincidunt elementum condimentum. Praesent molestie, nunc sed ullamcorper accumsan, augue urna maximus lorem, at venenatis orci tellus vitae leo.</p>
    <p>Pellentesque eget lacus sagittis, sollicitudin mauris eget, hendrerit est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sapien odio, ullamcorper in erat vitae, mollis vulputate leo.</p>
  </div>
 </div>
0 голосов
/ 26 апреля 2020

Итак, я нашел способ сделать это. В основном я пытаюсь изменить размер и переместить холст, основываясь на методе getBoundingClientRect ( см. Документацию ), каждый раз, когда размер окна изменяется:

class ParticleBackgroundComponent extends Component{
    constructor(props){
        super(props);

        //to help us get the boundingClientRect
        this.selector = React.createRef();

        //our state variables that store dimensions an position of the background
        this.state = {
            width: 0,
            height: 0,
            top: 0
        };
    }

    componentDidMount() {
        /*the first event listener to figure out when the page is done loading
        (use this if you have images in the component)*/
        window.addEventListener('load', () => {

            //setting the state to draw the background the first time
            var rect = this.selector.current.getBoundingClientRect();
            this.setState({
                width: rect.width,
                height: rect.height,
                top: rect.top + window.scrollY
            });

            //second event listener for resizing
            window.addEventListener('resize', ()=>{
                //redraw the background every time the page resizes 
                rect = this.selector.current.getBoundingClientRect();
                this.setState({
                    width: rect.width,
                    height: rect.height,
                    top: rect.top + window.scrollY
                })
            });

        });
    }

    //to render the particles
    renderBackground(){
        var width = this.state.width;
        var height = this.state.height;
        var top = this.state.top;

        //using a div to set the position of the background
        return (
            <div style={{position: "absolute", top: t, zIndex: -1}}>
                <Particles width={width} height={height}/>
            </div>
        )
    }

    render(){
        return (
            <div ref={this.selector}>

                <h1>
                    Some more content
                </h1>
                <p>
                    Lorem Ipsum dolor sit amet...
                </p>

                {this.renderBackground()}

            </div>
        )
    }
}

Какой длинный ответ. Я не думаю, что это лучший способ сделать это (и определенно не самый эффективный), так как я довольно плохо знаком с использованием React и даже Javascript в этом отношении. Если кто-то может улучшить этот ответ, непременно сделайте это

0 голосов
/ 25 апреля 2020

Вы ищете CSS element() function.

.dynamic-background {
  background: element(.particle-canvas);
}

Однако в настоящее время (апрель 2020 г.) он поддерживается только firefox с использованием нестандартного -moz-element() , Если вы планируете нацеливаться на большее количество браузеров в настоящее время, я рекомендую поискать альтернативные решения.

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