facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
228.09k stars 46.65k forks source link

d3.event is null in a ReactJS + d3JS component #6641

Closed varghesep closed 8 years ago

varghesep commented 8 years ago

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;
jimfb commented 8 years ago

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.

lgrkvst commented 8 years ago

Others with this issue will surely end up here, so here's an approach that worked for me:

  1. Open the (chrome) debugger's sources pane
  2. Set an event listener breakpoint for the event causing the issue
  3. Recreate the issue
  4. Execution should break into debug. Step forward until you're in d3 (particularly d3_selection_onListener(listener, argumentz)).
  5. Enter into console and save a global reference to the d3 object:

    > window.theD3versionHostingTheEvent = d3;

  6. Step forward until listener.apply(this, argumentz); and then choose Step into next function call until you get to the place throwing the error.
  7. Break into console again, and do: 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.

jbmusso commented 7 years ago

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.

hakuna0829 commented 3 years ago

Hi @jbmusso. Your code doesn't work with d3 v5. It occurs like this error.

Attempted import error: 'event' is not exported from 'd3' (imported as 'currentEvent').

Do you have any solution? Thanks

magdastone commented 3 years ago

I am working on a bursh-able parallel coordinates graph with d3 v6 in react. I have the exact same issue: Attempted import error: 'event' is not exported from 'd3-selection' (imported as 'currentEvent').

magdastone commented 3 years ago

okay. 1 minute later I appear to have found an answer: like written in this articlelet selected = d3.brushSelection(this); should fix the problem

KhRania commented 2 years ago

Hello i faced the same problem after using

import * as d3 from 'd3';
import {event as currentEvent} from 'd3';

I'm working with react v16 and d3 v7 and i'm using

const me = d3.select(this);

Any help please ?

guidoabelleira commented 2 years ago

Hola comunidad! Tengo el mismo problema. Estoy trabajando con "react 17.0.2" y "d3 7.2.0"