2017-02-15 12 views
0

Я создаю карту d3, объединив ее с React. В принципе, у меня есть mapchart компонент, который создает карту на основе этого подхода: http://bl.ocks.org/herrstucki/9238916Как правильно реализовать d3 svg click with React?

Я хочу, чтобы моя карта масштабируемой, нажав определенную государственную/Кантон/район и т.д., как показано здесь https://bl.ocks.org/mbostock/2206590

Таким образом, в основном я для добавления обработчика событий для click на svg, как показано на второй карте, которая вызывает функцию clicked().

Я попытался реализовать функцию clicked внутри React компонента, так:

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), 
    }) 
), 
); 

Однако при осуществлении щелкнул функции я столкнулся с проблемой.

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"); 
    } 

The path.centroid(d) не работает, так как стоимость d не кажется, правильный формат, и я не знаю, как будет выделен щелкнул состояние. В нормальной версии d3 d правильного состояния и формы данных, по-видимому, неявно передается функции. Как заставить компонент React выполнять то же самое?

ответ

1

Во-первых, как вы обнаружили, states.attr('d') это возвращая d атрибут пути, т.е. ... в <path d="..." />. Предполагается, что d на примере карты будет datum состояния, которое было нажато, то есть данные, привязанные к щелканному элементу DOM, который, в свою очередь, является записью из загруженного вами файла TopoJSON.

Поскольку вы создаете узлы DOM с использованием React, а не d3, нет данных, привязанных к элементам DOM. Это означает, что вам необходимо управлять связью между щелчком узла DOM и связанной с ним привязкой. Вы можете сделать это:

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

Таким образом, states будет передан clicked() в качестве своих первых пар:

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

Однако такой подход самого по себе не позволит вам знать, какой фактическое состояние было нажато, потому что вы рисуете ВСЕ состояния в один <path>. Пример d3 создает путь для каждого состояния, так что при клике по нему его базовым объектом является объект данных состояния. Чтобы сделать это равнозначно в React, вам нужно зациклиться и создать несколько путей. Мне сложно предоставить правильный код, потому что я не знаю содержимого states. Но при условии, что states представляет собой массив функций TopoJSON, более или менее необходимо работать (переключение на JSX здесь):

<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>