I'm using ReactJS, d3JS and ES6 to create an org chart. I can create the chart and see it. But I want to add the zoom and drag behavior to the chart, so I used d3.behavior.zoom. I can see the method zoomed is called, but the d3.event is null.
I tried attaching the zoom behavior to the div, svg and g but nothing helps. The zoomed behavior is called but the event is null.
In my ASP.NET project I made sure that I don't have any reference to d3.js other than in the systemJS configuration which many stackoverflow answers mentioned as the issue related to why d3.event is null.
My code is very similar to what is in an example like this https://github.com/Swizec/candidate-bucket-chart/blob/169779e110c8825f4545c71ae5845ff7bad4f1f4/src/BubbleChart.jsx which uses the old version of ReactJS.
This is my systemJS configuration:
<script>
System.defaultJSExtensions = true;
System.config({
map: {
'rx': "https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js",
'react': 'https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.js',
'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react-dom.js',
'd3': 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.js'
}
});
System.import('../app/app.js');
</script>
import React, { Component } from 'react';
import * as Rx from 'rx';
import * as d3 from 'd3';
import Person from './person';
class OrgChart extends Component {
constructor(props) {
super(props);
this.state = { persons: [] };
}
componentWillMount() {
// Just read a JSON file
var source = Rx.Observable.fromPromise($.getJSON("/js/org-persons.json"));
source.subscribe(
function(chart) {
var tree = d3.layout.tree()
.nodeSize([110, 50])
.separation(function() {
return 1;
});
var nodes = tree.nodes(chart[0]).reverse();
var links = tree.links(nodes);
var p = [];
nodes.forEach(function(node) {
fs.push((<Person x={node.x} y={node.y}></Person>));
}.bind(this));
this.setState({ person: p });
}.bind(this)
);
}
componentDidMount() {
var rootX = document.body.clientWidth / 4;
var rootY = 300;
// A standard setup with d3 to use it's zoom/drag behavior
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", this.zoomed)
.translate([rootX, rootY]);
// Attach zoom behavior to the first group in the svg.
d3.select("#viewport")
.call(zoom);
}
// When I drag the svg, this function gets called but the event is null. d3 is a global object.
zoomed() {
d3.select("#viewport").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// renders an org chart
render() {
return (
<div id='treeContainer'><svg id='fullTree' width='100%'>
<g id='viewport'>
{ this.state.persons }
</g>
</svg></div>
);
}
}
export default OrgChart;
The code you reference appears to be general d3 javascript, and the event does not pass through React's event system. This looks like a d3 question, unrelated to React. For this reason, I'm going to close out this issue.
On another note, you should use a ref
to reference a DOM node, NOT selecting by ID. Using things like d3.select("#viewport")
can cause interoperability issues with other components that happen to choose the same ID, and prevent a component from being used multiple times on the same page. Using a ref
will solve these issues.
Others with this issue will surely end up here, so here's an approach that worked for me:
> window.theD3versionHostingTheEvent = d3;
listener.apply(this, argumentz);
and then choose Step into next function call until you get to the place throwing the error.window.theD3versionHostingTheEvent == d3
If the result is false
, you're definitely running two instances of d3. In my case, it turned out one of the libs I was using had d3 bundled into it.
It's very likely that you're using Babel, which has trouble importing a mutable field from d3 using the import / export syntax.
See this: https://github.com/d3/d3/issues/2733#issuecomment-190743489
You'll want to change the way you import d3 with the following:
import * as d3 from 'd3';
import {event as currentEvent} from 'd3';
And replace all occurences of d3.event
with currentEvent
.
This fixes the issue with d3.js v3.
Most helpful comment
It's very likely that you're using Babel, which has trouble importing a mutable field from d3 using the import / export syntax.
See this: https://github.com/d3/d3/issues/2733#issuecomment-190743489
You'll want to change the way you import d3 with the following:
And replace all occurences of
d3.event
withcurrentEvent
.This fixes the issue with d3.js v3.