如何在Meteor-React设置中使用D3-force渲染D3?

时间:2018-01-23 18:35:29

标签: css reactjs d3.js meteor svg

我试图将this放在我的登录框后面。 svg元素正在渲染但没有内容。登录屏幕的其余部分以及网站的其余部分按预期工作。即使我注释掉所有其他的html和JSX代码,svg也不会在其中渲染粒子。我甚至还有另一个D3元素(只是一个图形)渲染得很好,所以我怀疑D3-force存在问题。我从npm安装了最新的d3和d3-force。

这里是所有相关的CSS:

* {
  margin: 0;
  padding: 0;
}

html {
  font-size: 62.5%;
}

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: $base-font-size;
  //background-color: $grey;
}

.boxed-view {
  align-items: center;
  background: $boxed-view-overlay-bg;
  display: flex;
  justify-content: center;
  height: 100vh;
  width: 100vw;
}

.boxed-view__box {
  background-color: $boxed-view-bg;
  margin-bottom: $space;
  padding: 2.4rem;
  text-align: center;
  width: 28rem;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  overflow: scroll;
}

以下是所有相关的JS:

import d3 from 'd3';
import React from 'react';
import d3_force from 'd3-force';
import {Session} from 'meteor/session';
import {Tracker} from 'meteor/tracker';

import {Bodies} from '../api/bodies';

export default class BrownianSplash extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      bodies: [],
      isOpen_add: false,
      isOpen_view: false,
      error: ''
    };
  }
  onSubmit(e) {
    let username = this.refs.username.value.trim();
    let password = this.refs.password.value.trim();
    e.preventDefault(); // prevent page refresh
    Meteor.loginWithPassword({username}, password, (err) => {
      if (err) {
        console.log('Login callback', err);
        this.setState({error: err.reason});
      } else {
        this.setState({error: ''});
      }
    });
  }
  componentDidMount() {
    this.bodyNamesTracker = Tracker.autorun(() => {
      Meteor.subscribe('bodies_names');
      const bodies = Bodies.find({}).fetch();
      this.setState({bodies});
    });
  }
  componentWillUnmount() {
    this.bodyNamesTracker.stop(); // we don't want to set the state every time the page is loaded
  }
  renderAnimation() {
    const INIT_DENSITY = 0.00025, // particles per sq px
      PARTICLE_RADIUS_RANGE = [1, 12],
      PARTICLE_VELOCITY_RANGE = [0, 4];

    const canvasWidth = window.innerWidth,
        canvasHeight = window.innerHeight,
        svgCanvas = d3.select('svg#canvas')
            .attr('width', canvasWidth)
            .attr('height', canvasHeight);

    const forceSim = d3_force.forceSimulation()
        .alphaDecay(0)
        .velocityDecay(0)
        .on('tick', particleDigest)
        .force('bounce', d3_force.forceBounce()
            .radius(d => d.r)
        )
        .force('container', d3_force.forceSurface()
            .surfaces([
                {from: {x:0,y:0}, to: {x:0,y:canvasHeight}},
                {from: {x:0,y:canvasHeight}, to: {x:canvasWidth,y:canvasHeight}},
                {from: {x:canvasWidth,y:canvasHeight}, to: {x:canvasWidth,y:0}},
                {from: {x:canvasWidth,y:0}, to: {x:0,y:0}}
            ])
            .oneWay(true)
            .radius(d => d.r)
        );

    // Init particles
    onDensityChange(INIT_DENSITY);

    // Event handlers
    function onDensityChange(density) {
        const newNodes = genNodes(density);
        // d3.select('#numparticles-val').text(newNodes.length);
        // d3.select('#density-control').attr('defaultValue', density);
        forceSim.nodes(newNodes);
    }

    function onElasticityChange(elasticity) {
        // d3.select('#elasticity-val').text(elasticity);
        // forceSim.force('bounce').elasticity(elasticity);
        // forceSim.force('container').elasticity(elasticity);
    }

    //

    function genNodes(density) {
        const numParticles = Math.round(canvasWidth * canvasHeight * density),
            existingParticles = forceSim.nodes();

        // Trim
        if (numParticles < existingParticles.length) {
            return existingParticles.slice(0, numParticles);
        }

        // Append
        return [...existingParticles, ...d3_force.range(numParticles - existingParticles.length).map(() => {
            const angle = Math.random() * 2 * Math.PI,
                velocity = Math.random() * (PARTICLE_VELOCITY_RANGE[1] - PARTICLE_VELOCITY_RANGE[0]) + PARTICLE_VELOCITY_RANGE[0];

            return {
                x: Math.random() * canvasWidth,
                y: Math.random() * canvasHeight,
                vx: Math.cos(angle) * velocity,
                vy: Math.sin(angle) * velocity,
                r: Math.round(Math.random() * (PARTICLE_RADIUS_RANGE[1] - PARTICLE_RADIUS_RANGE[0]) + PARTICLE_RADIUS_RANGE[0])
            }
        })];
    }

    function particleDigest() {
        let particle = svgCanvas.selectAll('circle.particle').data(forceSim.nodes().map(hardLimit));

        particle.exit().remove();

        particle.merge(
            particle.enter().append('circle')
                .classed('particle', true)
                .attr('r', d=>d.r)
                .attr('fill', 'darkslategrey')
        )
            .attr('cx', d => d.x)
            .attr('cy', d => d.y);
    }

    function hardLimit(node) {
        // Keep in canvas
        node.x = Math.max(node.r, Math.min(canvasWidth-node.r, node.x));
        node.y = Math.max(node.r, Math.min(canvasHeight-node.r, node.y));
        return node;
    }
  }
  render() {
    return (
      <div>
      <svg id="canvas"></svg>
      <div id="controls"></div>
      <div className='boxed-view'>
        {/* D3 background goes here */}
        {/* <svg className='boxed-view'></svg> */}
        <div className='boxed-view__box'>
          <h1>Login</h1>
          {this.state.error ? <p>{this.state.error}</p> : undefined}
          <form onSubmit={this.onSubmit.bind(this)} className='boxed-view__form'>
            <input type="text" name='username' placeholder="Josiah Carberry" ref='username'/>
            <input type="password" name='password' ref='password'/>
            <button className='button'>Let's Go</button>
          </form>
        </div>
      </div>
    </div>
    );
  }
}

1 个答案:

答案 0 :(得分:0)

所以我不知道d3-force-bounced3-force-surface存在。它们都是npm包并且是默认导出。方法d3.forceBounce()d3.forceSurface()d3ForceBounced3ForceSurface的方法,而不是d3。最后,我忘了在JSX中调用renderAnimation()