我试图将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>
);
}
}
答案 0 :(得分:0)
所以我不知道d3-force-bounce和d3-force-surface存在。它们都是npm包并且是默认导出。方法d3.forceBounce()
和d3.forceSurface()
是d3ForceBounce
和d3ForceSurface
的方法,而不是d3。最后,我忘了在JSX中调用renderAnimation()
。