d3.js
Använda D3 med andra ramverk
Sök…
D3.js-komponent med ReactJS
Detta exempel är baserat på ett blogginlägg av Nicolas Hery . Den använder ES6-klasser och ReactJSs livscykelmetoder för att hålla D3-komponenten uppdaterad
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'));
Placera innehållet i d3_react.html
och d3_react.js
i samma katalog och navigera i en webbläsare till d3React.html-filen. Om allt går bra, kommer du att se en rubrik som anger Hello, D3.js and React!
återges från React-komponenten och en röd rektangel nedan från den anpassade D3-komponenten.
React använder refs för att "nå ut" till komponentinstansen. Livscykelmetoderna i klassen d3React
kräver att denna ref lägger till, modifierar och tar bort DOM-element. d3React
kan utökas för att skapa fler anpassade komponenter och infoga var som helst en div.d3Component
skapas av React.
D3js med vinkel
Att använda D3js med Angular kan öppna nya fronter av möjligheter som live-uppdatering av diagram så snart data uppdateras. Vi kan kapsla in komplett kartfunktion inom ett vinkeldirektiv, vilket gör det lätt att återanvända.
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>
Vi kan skicka uppgifterna till diagrammet med hjälp av controller och titta på eventuella ändringar i uppgifterna för att möjliggöra liveuppdatering av diagrammet i direktivet:
app.js >>
angular.module('myApp', [])
.controller('MyCtrl', function($scope) {
$scope.data = [50, 40, 30];
$scope.$watch('data', function(newVal, oldVal) {
$scope.data = newVal;
}, true);
});
Slutligen direktivets definition. Koden vi skriver för att skapa och manipulera diagrammet kommer att sitta i direktivets länkfunktion.
Observera att vi har lagt en räckvidd. $ -Klocka i direktivet också för att uppdatera så snart kontrollenheten skickar ny data. Vi tilldelar ny data till vår datavariabel om det sker någon dataförändring och kallar sedan repaintChart () -funktionen, som utför diagrammet.
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);
})
}
}
}
});
Här är den fungerande JSFiddle.
D3.js-diagram med 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
}