【问题标题】:d3.event is null in a ReactJS + d3JS componentd3.event 在 ReactJS + d3JS 组件中为空
【发布时间】:2016-08-21 14:38:11
【问题描述】:

我正在使用 ReactJS、d3JS 和 ES6 来创建组织结构图。我可以创建图表并查看它。但我想在图表中添加缩放行为,所以我使用了 d3.behavior.zoom。我可以看到方法 zoomed 被调用,但 d3.event 为空。

在我的 ASP.NET 项目中,我确保除了在 systemJS 配置中没有任何对 d3.js 的引用,许多 stackoverflow 的答案都提到了与 相关的问题d3.event 为空。

这是我的 systemJS 配置:

<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() {
        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;

        var zoom = d3.behavior.zoom()
            .scaleExtent([1, 10])
            .on("zoom", this.zoomed)
            .translate([rootX, rootY]);

        d3.select("#viewport")
            .call(zoom);
    }

    zoomed() {
        d3.select("#viewport").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }

    render() {

        return (
            <svg id='fullTree' width='100%'>
                <g id='viewport'>
                    { this.state.persons }
                </g>
            </svg>
        );
    }
}

export default OrgChart;

【问题讨论】:

  • 你解决了吗?我对 d3 v3.x 有同样的问题,并且对 15.3.2 做出反应。 d3.event 始终为空。

标签: d3.js reactjs system


【解决方案1】:

快拍,试试这个。

    var zoom = d3.behavior.zoom()
        .scaleExtent([1, 10])
        .on("zoom", () => d3.select("#viewport").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");)
        .translate([rootX, rootY]);

如果这可行,那么以下应该可以解决您的问题,

var zoom = d3.behavior.zoom()
            .scaleExtent([1, 10])
            .on("zoom", this.zoomed.bind(this))
            .translate([rootX, rootY]);

【讨论】:

  • 你能把 d3 作为参数传递给回调函数,比如 .on("zoom", (d3) => d3.select("#viewport").attr("transform", "translate( " + d3.event.translate + ")scale(" + d3.event.scale + ")");)
【解决方案2】:

我不确定究竟你在做什么,但闻起来像是你想多了。理论上,缩放行为会改变比例范围。

因此,您所要做的就是将您的可视化建立在两个尺度上——一个用于x 坐标,一个用于y 坐标。然后你告诉 zoom 来改变这些比例,你的可视化就会自动改变。

基本上,放大只是意味着xy 映射得更宽。在zoom-level = 1,一个概念坐标(0.1, 0.1) 映射到,比如说,(10, 10)。当缩放级别更改为 2 时,相同的映射变为 (20, 20)。这会产生放大的印象。

这是我使用此原理创建缩放的一些旧代码:https://github.com/Swizec/candidate-bucket-chart/blob/169779e110c8825f4545c71ae5845ff7bad4f1f4/src/BubbleChart.jsx

React 本身现在有点过时了,我还没有时间将缩放推断为一个更干净的示例项目,但我希望它会有所帮助。

记住forceUpdate,因为 React 不知道你的比例发生了变化。

【讨论】:

  • 我将我的代码与您的进行了比较。它是相同的,并且在正确的 API 上进行的调用会做出反应。但我将 d3.event 中的事件设为空。如果你看到 d3.event 中的事件不为空,那么这个问题可能是 ReactJS 相关的 1.15,因为我使用的是这个。
【解决方案3】:

您是否尝试过像这样导入 d3: import d3 from 'd3';

当文档中存在两次 d3 时,似乎会出现此问题。

【讨论】:

    【解决方案4】:

    如果您要导入多个 d3 包。 这些包有一个可访问的 d3 对象,该对象可能会相互冲突。您必须使用不同的名称导入它们。

    import d3 from 'd3-selection'
    import d3Zoom from 'd3-zoom'
    import d3Scale from 'd3-scale'
    

    并为您的回调提供匿名函数

    .on("zoom", () => d3.select("#viewport")
        .attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    )
    

    【讨论】:

    • 你为什么要导入import d3Scale from 'd3-scale'
    • import d3Scale from 'd3-scale' 仅作为示例添加。与上面的sn-p无关。
    • 这应该是公认的答案。出于某种原因,从d3-selection 导入event 对我不起作用,而import d3 from d3-selection 解决了问题!
    【解决方案5】:

    如果您使用 React、Babel 或 Webpack 和 d3.js v4,您似乎需要从 d3-selection 导入 event 才能使用 d3.event

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

    您现在可以像使用d3.event 一样使用currentEvent。请参阅https://github.com/d3/d3/issues/2733 了解更多信息。

    【讨论】:

    • 我遇到了同样的问题,但使用的是d3 v3。我很幸运import {event as currentEvent} from 'd3';source
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    相关资源
    最近更新 更多