forked from kay-is/react-from-zero
-
Notifications
You must be signed in to change notification settings - Fork 0
/
16-advanced-integration.html
137 lines (106 loc) · 3.8 KB
/
16-advanced-integration.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<!doctype html>
<title>16 Advanced Integration - React From Zero</title>
<script src="https://unpkg.com/[email protected]/dist/react.js"></script>
<script src="https://unpkg.com/[email protected]/dist/react-dom.js"></script>
<script src="https://unpkg.com/[email protected]/browser.min.js"></script>
<script src="https://unpkg.com/[email protected]/build/d3.min.js">
// Sometimes we need to integrate more complex
// libraries. Libraries that want to use the
// DOM directly or require asynchronous interaction.
// In this example we use D3.js, a free InfoVis library.
</script>
<div id="app"></div>
<script type="text/babel">
// Since D3 needs to interact directly with the DOM we
// should use a component class, because it can store
// references to its DOM-elements.
var Visual = React.createClass({
// We simply render an empty canvas and tell React to
// store its reference after the render
render: function() {
return <canvas ref={this.handleRef} width={500} height={500}/>
},
handleRef: function(canvas) {
this.canvas = canvas
},
// After the first render, we grab the reference
// to the canvas element in the DOM and pass it
// to the library
componentDidMount: function() {
// Here we also use some additional color configuration
drawGraph(this.canvas, this.props.color)
},
// We also have some fine-granular control over the re-render
// With the use of this lifecylce method
shouldComponentUpdate: function(nextProps, nextState) {
// Here we could tell our library the new data for props
// or state, so it can update the DOM elements on its own
// At the end we always return false so our render method
// isn't called and the canvas element isn't replaced
return false
},
// This lifecycle method can be used to free resources
// before the component will be removed from the DOM.
// Our canvas will be removed for sure, but often there
// is state for the library, other objects, listeners etc.
// they could be stored at this and should be deleted to
// prevent memory leaks
componentWillUnmount() {},
})
// Now we can use the library as a component
// No need for global IDs, every instance has its own canvas
// reference stored, also its own color property
var reactElement =
<div>
<Visual color='#f00'/>
<Visual color='#0f0'/>
<Visual color='#00f'/>
</div>
ReactDOM.render(reactElement, document.getElementById('app'))
// Wrapping the library interaction into a function
function drawGraph(canvas, strokeColor) {
// An example from http://bl.ocks.org/mbostock/1b64ec067fcfc51e7471d944f51f1611
// its realeased under the GPL-V3
var n = 20
var nodes = d3.range(n * n).map(function(i) {
return {index: i}
})
var links = []
for (var y = 0; y < n; ++y) {
for (var x = 0; x < n; ++x) {
if (y > 0) links.push({source: (y - 1) * n + x, target: y * n + x});
if (x > 0) links.push({source: y * n + (x - 1), target: y * n + x});
}
}
d3.forceSimulation(nodes)
.force('charge', d3.forceManyBody().strength(-30))
.force('link', d3.forceLink(links).distance(20).iterations(10))
.on('tick', ticked)
var context = canvas.getContext('2d')
var width = canvas.width
var height = canvas.height
function ticked() {
context.clearRect(0, 0, width, height)
context.save()
context.translate(width / 2, height / 2)
context.beginPath()
links.forEach(drawLink)
context.strokeStyle = '#aaa'
context.stroke()
context.beginPath()
nodes.forEach(drawNode)
context.fill()
context.strokeStyle = strokeColor
context.stroke()
context.restore()
}
function drawLink(d) {
context.moveTo(d.source.x, d.source.y)
context.lineTo(d.target.x, d.target.y)
}
function drawNode(d) {
context.moveTo(d.x + 3, d.y);
context.arc(d.x, d.y, 3, 0, 2 * Math.PI)
}
}
</script>