Ravi Ojha
Ravi Ojha

Reputation: 168

d3.event is getting null in typescript implementation

this is here the two implementation doing the same thing, here i tried to produce the minimum repo, with two implementation. This one is without using typed definition of D3

    import React from 'react';

export class ChartExample extends React.Component {
    constructor(props) {
        super();
    }

    componentDidMount() {
        let margin = {top: -5, right: -5, bottom: -5, left: -5},
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

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

        this.svg = d3.select(React.findDOMNode(this))
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
            .call(this.zoom);

            let rect = this.svg.append("rect")
                .attr("width", width)
                .attr("height", height)
                .style("fill", "none")
                .style("pointer-events", "all");

            this.container = this.svg.append("g");
            this.container.append("g")
                .attr("class", "x axis")
                .selectAll("line")
                .data(d3.range(0, width, 10))
                .enter().append("line")
                .attr("x1", function(d) { return d; })
                .attr("y1", 0)
                .attr("x2", function(d) { return d; })
                .attr("y2", height);

            this.container.append("g")
                .attr("class", "y axis")
                .selectAll("line")
                .data(d3.range(0, height, 10))
                .enter().append("line")
                .attr("x1", 0)
                .attr("y1", function(d) { return d; })
                .attr("x2", width)
                .attr("y2", function(d) { return d; });
    }
    zoomed() {
        this.container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }

    render() {
        return <svg height={400} width={500}></svg>;
    }
}

Here Using the Typed definition of D3,

/// <reference path="../../../tsd.d.ts" />
import * as React from "react";
import * as d3 from "d3";

export class ExampleGraph extends React.Component<{}, {}> {
    private i: d3.Primitive;
    private duration: d3.Primitive;
    private svg: d3.Selection<d3.selection.Group>;
    private zoom: d3.behavior.Zoom<d3.selection.Group>;
    private container: d3.Selection<d3.selection.Group>
    constructor() {
        super();
    }
    componentDidMount(): void {
        let margin = {top: -5, right: -5, bottom: -5, left: -5},
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

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

        this.svg = d3.select(React.findDOMNode(this))
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
            .call(this.zoom);

        let rect = this.svg.append("rect")
            .attr("width", width)
            .attr("height", height)
            .style("fill", "none")
            .style("pointer-events", "all");

        this.container = this.svg.append("g");
        this.container.append("g")
            .attr("class", "x axis")
            .selectAll("line")
            .data(d3.range(0, width, 10))
            .enter().append("line")
            .attr("x1", function(d) { return d; })
            .attr("y1", 0)
            .attr("x2", function(d) { return d; })
            .attr("y2", height);

        this.container.append("g")
            .attr("class", "y axis")
            .selectAll("line")
            .data(d3.range(0, height, 10))
            .enter().append("line")
            .attr("x1", 0)
            .attr("y1", function(d) { return d; })
            .attr("x2", width)
            .attr("y2", function(d) { return d; });
    }
    zoomed(): void {
        this.container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }
    render(): JSX.Element {
        return <svg height={500} width={500}></svg>;
    }
}

Both doing the same thing, this is just the minimum implementation of showing Zoming,

But for some reason (in typed implementation , 2nd one) when i tried to zoom (Using wheel), the breakpoint is getting hit to zoomed function but d3.event is getting null, which is perfectly fine on the other implementation (without TypeScript) Can some please help me with this, may be i am registering zoom event in a wrong way, Please suggest, Any suggestion will be really helpful.

In TypeScript implementation the compiler is also giving error saying :

Property 'translate' does not exist on type 'Event.
Property 'scale' does not exist on type 'Event'.

Upvotes: 1

Views: 2132

Answers (2)

darcyparker
darcyparker

Reputation: 1219

I had a similar problem. The issue was import * as d3 from "d3";. In order to get access to d3.events you need to import d3 from 'd3';. A similar issue can occur with some features of moment. See http://www.typescriptlang.org/docs/handbook/modules.html#import

Upvotes: 1

Ravi Ojha
Ravi Ojha

Reputation: 168

This is how i fixed this:

// Here you create your zoom listener...
this.zoomListener = d3.behavior.zoom<d3Common.INode>()
            .scaleExtent(this.props.graphConfig.scaleExtent)
            .on('zoom', () => this.zoomHandler());

// here you get your scale and translate from your above zoom listener listener...
private zoomHandler(value: number): void {
        this.svg.attr('transform', 'translate(${this.zoomListener.translate()})scale(${this.zoomListener.scale()})');
    }

Upvotes: 1

Related Questions