Suche…


D3.js-Komponente mit ReactJS

Dieses Beispiel basiert auf einem Blogeintrag von Nicolas Hery . Es verwendet ES6-Klassen und die Lebenszyklusmethoden von ReactJS, um die D3-Komponente auf dem neuesten Stand zu halten


d3_react.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Hello, d3React!</title>
  <style>
    .d3Component {
      width: 720px;
      height: 120px;
    }
  </style>
</head>
<script src="https://fb.me/react-15.2.1.min.js"></script>
<script src="https://fb.me/react-dom-15.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>

<body>
  <div id="app" />
  <script type="text/babel" src="d3_react.js"></script>
</body>

</html>

d3_react.js

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      d3React: new d3React()
    };
    this.getd3ReactState = this.getd3ReactState.bind(this);
  }

  getd3ReactState() {
    // Using props and state, calculate the d3React state
    return ({
      data: {
        x: 0,
        y: 0,
        width: 42,
        height: 17,
        fill: 'red'
      }
    });
  }

  componentDidMount() {
    var props = {
      width: this._d3Div.clientWidth,
      height: this._d3Div.clientHeight
    };
    var state = this.getd3ReactState();
    this.state.d3React.create(this._d3Div, props, state);
  }

  componentDidUpdate(prevProps, prevState) {
    var state = this.getd3ReactState();
    this.state.d3React.update(this._d3Div, state);
  }

  componentWillUnmount() {
    this.state.d3React.destroy(this._d3Div);
  }

  render() {
    return (
      <div>
        <h1>{this.props.message}</h1>
        <div className="d3Component" ref={(component) => { this._d3Div = component; } } />
      </div>
    );
  }
}

class d3React {
  constructor() {
    this.create = this.create.bind(this);
    this.update = this.update.bind(this);
    this.destroy  = this.destroy.bind(this);
    this._drawComponent = this._drawComponent.bind(this);
  }

  create(element, props, state) {
    console.log('d3React create');
    var svg = d3.select(element).append('svg')
      .attr('width', props.width)
      .attr('height', props.height);

    this.update(element, state);
  }

  update(element, state) {
    console.log('d3React update');
    this._drawComponent(element, state.data);
  }

  destroy(element) {
    console.log('d3React destroy');
  }

  _drawComponent(element, data) {
    // perform all drawing on the element here
    var svg = d3.select(element).select('svg');

    svg.append('rect')
      .attr('x', data.x)
      .attr('y', data.y)
      .attr('width', data.width)
      .attr('height', data.height)
      .attr('fill', data.fill);
  }
}

ReactDOM.render(<App message="Hello, D3.js and React!"/>, document.getElementById('app'));

d3_react.html d3_react.js den Inhalt von d3_react.html und d3_react.js im selben Verzeichnis ab und navigieren Sie mit einem Webbrowser zur Datei d3React.html. Wenn alles gut geht, sehen Sie eine Kopfzeile mit Hello, D3.js and React! gerendert aus der React-Komponente und einem roten Rechteck darunter aus der benutzerdefinierten D3-Komponente.

React verwendet refs , um die Komponenteninstanz zu erreichen. Die Lebenszyklusmethoden der d3React Klasse erfordern, dass dieser d3React DOM-Elemente d3React , ändert und entfernt. Die d3React Klasse kann erweitert werden, um weitere benutzerdefinierte Komponenten zu erstellen, und an einer div.d3Component Stelle eingefügt, an der eine div.d3Component von React erstellt wird.

D3js mit Winkel

Die Verwendung von D3js mit Angular kann neue Möglichkeiten eröffnen, z. B. die Live-Aktualisierung von Diagrammen, sobald die Daten aktualisiert werden. Wir können die vollständige Diagrammfunktionalität in einer Angular-Direktive kapseln, sodass sie leicht wiederverwendbar ist.

index.html >>

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script data-require="[email protected]" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
  <script src="app.js"></script>
  <script src="bar-chart.js"></script>
</head>

<body>

  <div ng-controller="MyCtrl">
    <!-- reusable d3js bar-chart directive, data is sent using isolated scope -->
    <bar-chart data="data"></bar-chart>
  </div>

</body>
</html>

Wir können die Daten mithilfe eines Controllers an das Diagramm übergeben und auf Änderungen in den Daten achten, um eine Live-Aktualisierung des Diagramms in der Anweisung zu ermöglichen:

app.js >>

angular.module('myApp', [])
  .controller('MyCtrl', function($scope) {
    $scope.data = [50, 40, 30];
    $scope.$watch('data', function(newVal, oldVal) {
      $scope.data = newVal;
    }, true);
  });

Schließlich die Definition der Richtlinie. Der Code, den wir zum Erstellen und Bearbeiten des Diagramms schreiben, wird in der Link-Funktion der Direktive gespeichert.

Beachten Sie, dass wir auch einen Geltungsbereich. $ Watch in die Direktive eingefügt haben, der aktualisiert wird, sobald der Controller neue Daten übergibt. Wir ordnen unserer Datenvariablen neue Daten zu, wenn sich Daten ändern, und rufen dann die Funktion repaintChart () auf, die das erneute Rendern des Diagramms durchführt.

bar-chart.js >>

angular.module('myApp').directive('barChart', function($window) {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      data: '='
    },
    template: '<div id="bar-chart"></div>',
    link: function(scope, element, attrs, fn) {

      var data = scope.data;
      var d3 = $window.d3;
      var rawSvg = element;

      var colors = d3.scale.category10();

      var canvas = d3.select(rawSvg[0])
        .append('svg')
        .attr("width", 300)
        .attr("height", 150);

      // watching for any changes in the data
      // if new data is detected, the chart repaint code is run
      scope.$watch('data', function(newVal, oldVal) {
        data = newVal;
        repaintChart();
      }, true);

      var xscale = d3.scale.linear()
        .domain([0, 100])
        .range([0, 240]);

      var yscale = d3.scale.linear()
        .domain([0, data.length])
        .range([0, 120]);

      var bar = canvas.append('g')
        .attr("id", "bar-group")
        .attr("transform", "translate(10,20)")
        .selectAll('rect')
        .data(data)
        .enter()
        .append('rect')
        .attr("class", "bar")
        .attr("height", 15)
        .attr("x", 0)
        .attr("y", function(d, i) {
          return yscale(i);
        })
        .style("fill", function(d, i) {
          return colors(i);
        })
        .attr("width", function(d) {
          return xscale(d);
        });

      // changing the bar widths according to the changes in data
      function repaintChart() {
        canvas.selectAll('rect')
          .data(data)
          .transition()
          .duration(800)
          .attr("width", function(d) {
            return xscale(d);
          })
      }
    }
  }
});

Hier ist das funktionierende JSFiddle.

D3.js-Diagramm mit Angular v1

HTML:

<div ng-app="myApp" ng-controller="Controller">
    <some-chart data="data"></some-chart>
</div>

Javascript:

angular.module('myApp', [])
.directive('someChart', function() {
    return {
        restrict: 'E',
        scope: {data: '=data'},
        link: function (scope, element, attrs) {
        var chartElement = d3.select(element[0]);
            // here you have scope.data and chartElement
            // so you may do what you want
        } 
    };
});

function Controller($scope) {
    $scope.data = [1,2,3,4,5]; // useful data
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow