2015-12-26 21 views
7

Załóżmy, że mam element SVG ze ścieżkami dla wszystkich stanów USA.Tworzenie interaktywnego komponentu SVG za pomocą React

<svg> 
    <g id="nh"> 
     <title>New Hampshire</title> 
     <path d="m 880.79902,142.42476 0.869,-1.0765 1.09022,..." id="NH" class="state nh" /> 
    </g> 
    ... 
</svg> 

Dane SVG są zapisywane w oddzielnym pliku z rozszerzeniem .svg. Załóżmy, że chcę utworzyć komponent React na tej mapie, z pełną kontrolą nad nim, aby móc modyfikować stylizację poszczególnych stanów na podstawie danych wejściowych z zewnątrz.

Korzystanie WebPACK, o ile mogę powiedzieć, mam dwie opcje ładowania znaczników SVG: Włóż go jako surowego znaczników za pomocą raw-loader i utworzyć komponent używając dangerouslySetInnerHTML:

var InlineSvg = React.createClass({ 
    render() { 
    var svg = require('./' + this.props.name + '.svg'); 
    return <div dangerouslySetInnerHTML={{__html: svg}}></div>; 
    } 
}); 

lub ręcznie przekonwertować znaczników do ważnego JSX:

var NewComponent = React.createClass({ 
    render: function() { 
    return (
     <svg> 
      <g id="nh"> 
       <title>New Hampshire</title> 
       <path d="m 880.79902,142.42476 0.869,-1.0765 1.09022,..." id="NH" className="state nh" /> 
      </g> 
      ... 
     </svg> 
    ); 
}); 

Wreszcie, powiedzmy, że oprócz mapie SVG, istnieje prosta lista HTML wszystkich stanach. Gdy użytkownik unosi się nad elementem listy, odpowiednia ścieżka SVG powinna zmienić kolor wypełnienia.

Teraz nie mogę się domyślić, jak zaktualizować komponent React SVG, aby odzwierciedlić stan ukryty. Oczywiście, mogę sięgnąć do DOM, wybrać stan SVG według nazwy klasy i zmienić jego kolor, ale to nie wydaje się być "reakcją", jak to zrobić. Wskazany palec byłby bardzo doceniany.

PS. Używam Redux do obsługi całej komunikacji między komponentami.

Odpowiedz

3

trzeba zrobić dwie rzeczy:

1) Ustawić detektor zdarzeń na każdym elemencie listy poinformować aplikację z zaznaczonego elementu.

<li 
    onMouseOver={() => this.handleHover('NH')} 
    onMouseOut={() => this.handleUnhover()} 
> 
    New Hampshire 
</li> 

2) Przechwytuj dane i propaguj je jako składnik SVG.

To jest bardziej skomplikowana część, a sprowadza się ona do sposobu organizacji aplikacji.

  • Jeśli cała aplikacja jest pojedynczym React komponent, a następnie handleHover po prostu zaktualizować stan komponentu
  • Jeśli aplikacja jest podzielony na wiele elementów, a następnie handleHover spowodowałoby zwrotnego przekazywana jako rekwizyt

Przyjmijmy to drugie. Metody elementów może wyglądać następująco:

handleHover(territory) { 
    this.props.onHighlight(territory); 
} 

handleUnhover() { 
    this.props.onHighlight(null); 
} 

Zakładając, że element nadrzędny, który zawiera zarówno mapę SVG i listy, może to wyglądać mniej więcej tak:

class MapWrapper extends React.Component { 

    constructor(props) { 
     super(props); 
     this.state = { 
      highlighted: null; 
     }; 
    } 

    setHighlight(territory) { 
     this.setState({ 
      highlighted: territory 
     }); 
    } 

    render() { 
     const highlighted = { this.state }; 
     return (
      <div> 
       <MapDiagram highlighted={highlighted} /> 
       <TerritoryList onHighlight={(terr) => this.setHighlight(terr)} /> 
      </div> 
     ); 
    } 

} 

Kluczem jest tu zmienna stanu highlighted. Za każdym razem, gdy pojawia się nowe zdarzenie najeżdżające, wartość highlighted zmienia się. Ta zmiana powoduje ponowne renderowanie, a nowa wartość jest przekazywana do , która może następnie określić, która część SVG ma być podświetlona.

+0

Wygląda świetnie, dzięki! Jedno jednak, klucz 'terytorium' w obiekcie stanu w' setHighlight' powinien być "podświetlony", prawda?Jest to zgodne z nazwą klucza w oryginalnym obiekcie stanu. –

+0

Dobre miejsce. Naprawiony. –

+1

Dla części "propaguj do SVG" stworzyłem https://www.npmjs.com/package/react-samy-svg. Ułatwia ładowanie i manipulowanie atrybutami elementów svg. –

Powiązane problemy