2017-02-15 2 views
0

Ich erstelle eine d3-Map, indem ich sie mit React integriere. Grundsätzlich habe ich eine mapchart Komponente, die die Karte nach diesem Ansatz schafft: http://bl.ocks.org/herrstucki/9238916Wie d3 svg Klick mit React richtig zu implementieren?

Ich möchte meine Karte zoombar, indem Sie einen bestimmten Zustand/Kanton/Bezirk klicken etc wie hier gezeigt https://bl.ocks.org/mbostock/2206590

Also, im Grunde habe ich Einen Ereignishandler für click auf der Svg hinzufügen, wie in der 2. Karte, die die clicked()-Funktion aufruft.

Ich versuchte, die clicked Funktion innerhalb der React Komponente als so zu implementieren:

return React.DOM.svg({width: this.props.width, height: this.props.height}, 
    React.DOM.g({ 
    width: this.props.width, 
    height: this.props.height, 
    }, 
    React.DOM.path({ 
     className: 'states', 
     d: path(states), 
     onClick: this.clicked, // ** added click event here ** 
    }), 
    React.DOM.path({ 
     className: 'state-borders', 
     d: path(stateBorders), 
    }) 
), 
); 

Wenn jedoch die angeklickt Funktion implementiert ich in ein Problem lief.

clicked() { 
    var states = select(ReactDOM.findDOMNode(this)).select('path.states'); 
    var d = states.attr('d'); // ** not what i thought it would be ** 

    var group = select(ReactDOM.findDOMNode(this)).select('g'); 

    var path = geoPath(); 
    var x, y, k; 
    var centered; 

    if (d && centered !== d) { 
     var centroid = path.centroid(d); 
     console.log(centroid) 
     x = centroid[0]; 
     y = centroid[1]; 
     k = 4; 
     centered = d; 
    } else { 
     x = this.props.width/2; 
     y = this.props.height/2; 
     k = 1; 
     centered = null; 
    } 

    group.selectAll("path") 
     .classed("active", centered && function(d) { return d === centered; }); 

    group.transition() 
     .duration(750) 
     .attr("transform", "translate(" + this.props.width/2 + "," + this.props.height/2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")") 
     .style("stroke-width", 1.5/k + "px"); 
    } 

Die path.centroid(d) funktioniert nicht, da der Wert von d nicht das richtige Format zu sein scheint, und ich bin nicht sicher, wie die geklickt Zustand hervorgehoben wird. In der normalen d3-Version scheint die d des korrekten Zustands und Datenformats implizit an die Funktion übergeben zu werden. Wie bekomme ich meine React-Komponente Funktion, um das gleiche zu tun?

Antwort

1

Zuerst wird, wie Sie entdeckt, states.attr('d') kehrt das d Attribut des Weges, das heißt die ... in <path d="..." />. Die d im Kartenbeispiel soll das Datum des Staates, der angeklickt wurde, d. H. Die Daten, die an das angeklickte DOM-Element gebunden ist, die wiederum ein Eintrag aus der TopoJSON-Datei ist.

Da Sie mit React anstelle von d3 DOM-Knoten erstellen, sind keine Daten an die DOM-Elemente gebunden. Dies bedeutet, dass Sie die Zuordnung zwischen dem angeklickten DOM-Knoten und dem zugehörigen Datum verwalten müssen. Sie können dies tun:

React.DOM.path({ 
    className: 'states', 
    d: path(states), 
    onClick: this.clicked.bind(this, states), // ** added click event here ** 
}) 

Auf diese Weise states wird clicked() als erstes param übergeben werden:

function clicked(d) { 
    // now you have d! 
} 

jedoch dieser Ansatz nicht allein nicht lassen Sie wissen, welche aktuellen Zustand geklickt wurde, weil du ALLE Zustände in eine einzige Zeichnung zeichnest <path>. Das d3-Beispiel erstellt einen Pfad pro Status. Wenn ein Pfad angeklickt wird, ist sein Datum das Datenobjekt dieses Status. Um es in React äquivalent auszuführen, müssen Sie mehrere Pfade in Schleife erstellen und erstellen. Es ist schwer für mich, den richtigen Code zur Verfügung zu stellen, da ich den Inhalt von states nicht kenne. Aber unter der Annahme, states ist ein Array von TopoJSON-Funktionen, sollte mehr oder weniger Folgendes funktionieren (hier zu JSX wechseln):

<svg width={this.props.width} height={this.props.height}> 
    <g>{ 
    states.map(function (state, i) { 
     return (<path 
     className='states' 
     key={'state_' + i} 
     d={path(state)} 
     onClick={this.clicked.bind(this, state)} 
     </path>) 
    }) 
    }</g> 
</svg>