我正在尝试使用remove方法删除条形图并插入一个新的条形图。当我在选择上执行remove()时,SVG内容将被清空,但是svg元素仍位于DOM中,并占用了屏幕空间。新版本的SVG被添加到空白版本的右侧。当我改为在包含的div上执行remove()时,svg完全消失了,但是当我调用代码以插入新版本时,不会创建新图表。
D3_BarChart.update = (el, data, configuration, chart) => {
// d3.select(el).remove();
chart.remove();
D3_BarChart.create(el, dataSubset, configuration);
};
我正在https://www.smashingmagazine.com/2018/02/react-d3-ecosystem/中描述的“生命周期方法包装”之后从React中执行D3代码,因此应该将两个库完全分开,并且不要相互运行。
D3代码
// d3 is not a top level export
import * as d3 from 'd3';
// Simple Bar Chart from D3 v4 example at https://bl.ocks.org/d3noob/bdf28027e0ce70bd132edc64f1dd7ea4
const D3_BarChart = {};
/* eslint-disable prefer-arrow-callback */
/* eslint-disable fun-names */
const dataSubset = `salesperson,sales
Bob,33
Robin,12`;
D3_BarChart.create = (el, data, configuration) => {
// D3 Code to create the chart
// Styling
el.style.fill = 'steelblue';
data = `salesperson,sales
Bob,33
Robin,12
Anne,41
Mark,16
Joe,59
Eve,38
Karen,21
Kirsty,25
Chris,30
Lisa,47
Tom,5
Stacy,20
Charles,13
Mary,29`;
// set the dimensions and margins of the graph
const margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
};
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// set the ranges
const x = d3
.scaleBand()
.range([0, width])
.padding(0.1);
const y = d3.scaleLinear().range([height, 0]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
const svg = d3
.select(el)
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// get the data
const parsedData = d3.csvParse(data);
// format the data
parsedData.forEach(function (d) {
d.sales = +d.sales;
});
// Scale the range of the data in the domains
x.domain(
parsedData.map(function (d) {
return d.salesperson;
})
);
y.domain([
0,
d3.max(parsedData, function (d) {
return d.sales;
})
]);
// append the rectangles for the bar chart
svg
.selectAll('.bar')
.data(parsedData)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('x', function (d) {
return x(d.salesperson);
})
.attr('width', x.bandwidth())
.attr('y', function (d) {
return y(d.sales);
})
.attr('height', function (d) {
return height - y(d.sales);
});
// add the x Axis
svg
.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
// add the y Axis
svg.append('g').call(d3.axisLeft(y));
return svg;
};
D3_BarChart.update = (el, data, configuration, chart) => {
// D3 Code to update the chart
console.log('update el', el);
console.log('update chart', chart);
d3.select(el).remove();
// chart.remove();
D3_BarChart.create(el, dataSubset, configuration);
};
D3_BarChart.destroy = () => {
// Cleaning code here
};
export default D3_BarChart;
反应容器
/* eslint-disable no-undef */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import Explore from '../components/Explore';
import D3_BarChart from '../components/d3/D3_BarChart';
import { resetErrorMessage } from '../actions';
class App extends Component {
static propTypes = {
// Injected by React Redux
errorMessage: PropTypes.string,
resetErrorMessage: PropTypes.func.isRequired,
inputValue: PropTypes.string.isRequired,
// Injected by React Router
children: PropTypes.node
};
constructor(props) {
super(props);
this.setBarChartContainerRef = this.setBarChartContainerRef.bind(this);
}
componentDidMount() {
// D3 Code to create the chart
this.d3_barChart = D3_BarChart.create(
this.d3_barChartContainerRef,
this.props.data,
this.props.config
);
setTimeout(() => {
D3_BarChart.update(this.d3_barChartContainerRef, this.props.data, this.props.config, this.d3_barChart);
}, 200);
}
handleDismissClick = e => {
this.props.resetErrorMessage();
e.preventDefault();
};
handleChange = nextValue => {
this.props.history.push(`/${nextValue}`);
};
renderErrorMessage() {
const { errorMessage } = this.props;
if (!errorMessage) {
return null;
}
return (
<p style={{ backgroundColor: '#e99', padding: 10 }}>
<b>{errorMessage}</b> <button onClick={this.handleDismissClick}>Dismiss</button>
</p>
);
}
setBarChartContainerRef(element) {
this.d3_barChartContainerRef = element;
}
render() {
const { children, inputValue } = this.props;
return (
<div className="d3-container" ref={this.setBarChartContainerRef.bind(this)}>
{/* <D3_BarChart value={inputValue} onChange={this.handleChange} /> */}
{/* <Explore value={inputValue} onChange={this.handleChange} />*/}
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
errorMessage: state.errorMessage,
inputValue: ownProps.location.pathname.substring(1)
};
};
export default withRouter(
connect(
mapStateToProps,
{
resetErrorMessage
}
)(App)
);
答案 0 :(得分:0)
create方法需要返回d3.select(el).select('svg')
,然后chart.remove()
起作用。