2017-02-06 2 views
0

Ich habe eine d3 Probe, die ich versuche, mit reagieren zu integrieren. Die Komponente sollte ein Array von Arrays als Datenpunkte aufnehmen (x ist Datum und y ist ein Gleitkommawert) und ein Liniendiagramm darstellen. Die Komponente ist wie folgt:d3 Bindung an falsche Komponente Instanz reagieren

import React, {Component} from 'react'; 
import * as d3 from "d3"; 

export default class Chart extends Component { 
    constructor(props){ 
    super(props); 
    } 

    componentDidMount(){ 
    this.buildLineChart(this.props.stock.dataset.data) 
    } 

    buildLineChart(data){ 
    var svg = d3.select("svg"), 
       margin = {top: 20, right: 20, bottom: 30, left: 50}, 
       width = +svg.attr("width") - margin.left - margin.right, 
       height = +svg.attr("height") - margin.top - margin.bottom, 
       g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

    var parseTime = d3.timeParse("%Y-%m-%d"); 

    var x = d3.scaleTime().rangeRound([0, width]); 
    var y = d3.scaleLinear().rangeRound([height, 0]); 

    var data = data.map(function(d){ 
     return [parseTime(d[0]), +d[1]] 
    }); 

    var line = d3.line() 
     .x(function(d){ 
     return x(d[0]) 
     }) 
     .y(function(d){ 
     return y(d[1]) 
     }); 

    x.domain(d3.extent(data, function(d) { return d[0]; })); 
    y.domain(d3.extent(data, function(d) { return d[1]; })); 

    g.append("g") 
     .attr("transform", "translate(0," + height + ")") 
     .call(d3.axisBottom(x)) 
     .select(".domain") 
     .remove(); 

    g.append("g") 
     .call(d3.axisLeft(y)) 
     .append("text") 
     .attr("fill", "#000") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 50) 
     .attr("dy", "0.6em") 
     .attr("text-anchor", "end"); 
     // .text("Price ($)"); 

    g.append("path") 
     .datum(data) 
     .attr("fill", "none") 
     .attr("stroke", "steelblue") 
     .attr("stroke-linejoin", "round") 
     .attr("stroke-linecap", "round") 
     .attr("stroke-width", 3) 
     .attr("d", line); 

    } 

    render() { 
    const divStyle = { 
     backgroundColor: '#D8D8D8', 
     borderStyle: 'solid', 
     borderWidth: 'thin', 
     borderRadius: '15px', 
     marginLeft: '10px', 
     marginRight: '10px' 
    }; 

    return(
     <div className="form-group row col-sm-12" style={divStyle}> 
      <div className="row" id="lineChartContainer"> 
      <svg width="768" height="300"></svg> 
      </div> 
     </div> 
    ); 
    } 
} 

ich eine Standard-Komponente haben, die Lasten und alles sieht gut aus. Wenn ich jedoch zusätzliche Komponentenexemplare spawne, während zusätzliche Komponenten rendern, schreibt d3 das neue Liniendiagramm über das alte. Was ich bekommen, ist eine Situation wie folgt aus: enter image description here

Facebook die Standard-Komponente und Lasten in Ordnung ist, aber wenn ich versuche und Spin eine Netflix-Komponente auf, wird die Instanz erzeugt, aber die NFLX Diagramm wird über oben die geschrieben Facebook-Diagramm. Gibt es eine einfache Konvention, um d3 an die eigene Komponenteninstanz zu binden?

+1

Nun, ich nie benutzt reagieren und so bin ich wohl falsch hier, aber nur FYI in reiner JS diese Zeile hinzu: ' var svg = d3.select ("svg") 'weist d3 an, das ** erste ** SVG auszuwählen, das im DOM gefunden wird. –

Antwort

1

Sie haben, wie unten das „svg“ Element innerhalb der Komponente zu wählen,

buildLineChart(data){ 
    var svg = d3.select(this.getDOMNode()).select("svg"), 
    .... 
} 
+0

Ich muss auf einer Version von React sein, wo getDOMNode veraltet ist, da ich einen Fehler erhalten habe, der angibt, dass es keine Funktion war. FindDOMNode (this) anstelle von this.getDOMNode() funktionierte, so wies mich diese Antwort auf das Problem hin. –