Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I install and use d3 with angular-cli@webpack? #1856

Closed
ghost opened this issue Aug 27, 2016 · 23 comments
Closed

How can I install and use d3 with angular-cli@webpack? #1856

ghost opened this issue Aug 27, 2016 · 23 comments

Comments

@ghost
Copy link

ghost commented Aug 27, 2016

Please provide us with the following information:

  1. OS? Windows 7, 8 or 10. Linux (which distribution). Mac OSX (Yosemite? El Capitan?)
    Mac OSX El Capitan
  2. Versions. Please run ng --version. If there's nothing outputted, please run
    in a Terminal: node --version and paste the result here:
    $ node --version
    v6.2.1
    $ npm --version
    3.10.6
  3. Repro steps. Was this an app that wasn't created using the CLI? What change did you
    do on your code? etc.
    • Created a project using angular-cli@1.0.0-beta.10.
    • Migrated it to RC5, using SystemJS
    • Installed d3@3.5.17 & a very simple D3 chart
    • OBSERVED BEHAVIOR: works
    • Upgraded the project to angular-cli@webpack
    • Upgraded to d3@4.2.2
    • OBSERVED BEHAVIOT: Unable to find D3
  4. The log given by the failure. Normally this include a stack trace and some
    more information.
    browser_adapter.js:84EXCEPTION: Error in ./AppComponent class AppComponent - inline template:12:12BrowserDomAdapter.logError @ browser_adapter.js:84BrowserDomAdapter.logGroup @ browser_adapter.js:94ExceptionHandler.call @ exception_handler.js:65(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
    browser_adapter.js:84ORIGINAL EXCEPTION: TypeError: Cannot read property 'style' of nullBrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:74(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
    browser_adapter.js:84ORIGINAL STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:77(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
    browser_adapter.js:84TypeError: Cannot read property 'style' of null
    at new BarGraphDirective (bar-graph.directive.ts:45)
    at DebugAppView._View_AppComponent0.createInternal (AppComponent.ngfactory.js:73)
    at DebugAppView.AppView.create (view.js:101)
    at DebugAppView.create (view.js:314)
    at DebugAppView.View_AppComponent_Host0.createInternal (AppComponent.ngfactory.js:18)
    at DebugAppView.AppView.create (view.js:101)
    at DebugAppView.create (view.js:314)
    at ComponentFactory.create (component_factory.js:156)
    at ApplicationRef
    .bootstrap (application_ref.js:516)
    at application_ref.js:374BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:78(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
    browser_adapter.js:84ERROR CONTEXT:BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:81(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
    browser_adapter.js:84DebugContext {_view: _View_AppComponent0, _nodeIndex: 20, _tplRow: 12, _tplCol: 12}BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:82(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
    zone.js:461 Unhandled Promise rejection: EXCEPTION: Error in ./AppComponent class AppComponent - inline template:12:12
    ORIGINAL EXCEPTION: TypeError: Cannot read property 'style' of null
    ORIGINAL STACKTRACE:
    TypeError: Cannot read property 'style' of null
    at new BarGraphDirective (http://localhost:4200/main.bundle.js:58185:13)
    at DebugAppView._View_AppComponent0.createInternal (AppComponent.ngfactory.js:73:34)
    at DebugAppView.AppView.create (http://localhost:4200/main.bundle.js:53955:21)
    at DebugAppView.create (http://localhost:4200/main.bundle.js:54168:44)
    at DebugAppView.View_AppComponent_Host0.createInternal (AppComponent.ngfactory.js:18:14)
    at DebugAppView.AppView.create (http://localhost:4200/main.bundle.js:53955:21)
    at DebugAppView.create (http://localhost:4200/main.bundle.js:54168:44)
    at ComponentFactory.create (http://localhost:4200/main.bundle.js:38625:36)
    at ApplicationRef
    .bootstrap (http://localhost:4200/main.bundle.js:25848:40)
    at http://localhost:4200/main.bundle.js:25706:89
    ERROR CONTEXT:
    [object Object] ; Zone: ; Task: Promise.then ; Value: ViewWrappedException {_wrapperMessage: "Error in ./AppComponent class AppComponent - inline template:12:12", _originalException: TypeError: Cannot read property 'style' of null
    at new BarGraphDirective (http://localhost:4200/…, _originalStack: "TypeError: Cannot read property 'style' of null↵ … at http://localhost:4200/main.bundle.js:25706:89", context: DebugContext, wrapperStack: "Error: Error in ./AppComponent class AppComponent … at http://localhost:4200/main.bundle.js:25706:89"}consoleError @ zone.js:461_loop_1 @ zone.js:490drainMicroTaskQueue @ zone.js:494
    zone.js:463 Error: Uncaught (in promise): EXCEPTION: Error in ./AppComponent class AppComponent - inline template:12:12(…)consoleError @ zone.js:463_loop_1 @ zone.js:490drainMicroTaskQueue @ zone.js:494
    injected.js:142 GET http://127.0.0.1:35729/livereload.js?ext=Chrome&extver=2.1.0 net::ERR_CONNECTION_REFUSEDLiveReloadInjected.doEnable @ injected.js:142(anonymous function) @ injected.js:180LiveReloadInjected.doDisable @ injected.js:119LiveReloadInjected.enable @ injected.js:178(anonymous function) @ injected.js:19target.(anonymous function) @ extensions::SafeBuiltins:19EventImpl.dispatchToListener @ extensions::event_bindings:388target.(anonymous function) @ extensions::SafeBuiltins:19publicClassPrototype.(anonymous function) @ extensions::utils:151EventImpl.dispatch
    @ extensions::event_bindings:372EventImpl.dispatch @ extensions::event_bindings:394target.(anonymous function) @ extensions::SafeBuiltins:19publicClassPrototype.(anonymous function) @ extensions::utils:151messageListener @ extensions::messaging:205target.(anonymous function) @ extensions::SafeBuiltins:19EventImpl.dispatchToListener @ extensions::event_bindings:388target.(anonymous function) @ extensions::SafeBuiltins:19publicClassPrototype.(anonymous function) @ extensions::utils:151EventImpl.dispatch
    @ extensions::event_bindings:372EventImpl.dispatch @ extensions::event_bindings:394target.(anonymous function) @ extensions::SafeBuiltins:19publicClassPrototype.(anonymous function) @ extensions::utils:151dispatchOnMessage @ extensions::messaging:336
    client:47 [WDS] Errors while compiling.
    client:49 [default] /Users/silveir/Projects/dlabs/wpack/src/app/directives/bar-graph.directive.ts:2:20
    Cannot find module 'd3'.
  5. Mention any other details that might be useful.

Thanks! We'll be in touch soon.

@evanrooijen
Copy link

+1

@deebloo
Copy link
Contributor

deebloo commented Aug 28, 2016

this is actually the example used in the readme for using 3rd party libs.
https://github.com/angular/angular-cli#3rd-party-library-installation

@evanrooijen
Copy link

After installing, how does the compiler know to add it to - for example - bundle.js? in my case nothing happens when trying to install for instance bootstrap4 or jquery

@dereklin
Copy link

After installation, d3 works, but there are type errors:

Property 'axisBottom' does not exist on type 'typeof d3'.

I am using d3 V4 and axisBottom is new in V4. Does it mean the type definition installed here is for d3 V3?

Since the type definition is from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/types-2.0/d3/index.d.ts, am I suppose to be able to find axisBottom there?

@ghost
Copy link
Author

ghost commented Aug 28, 2016

The problem I'm facing is with the new angular-cli@webpack. My prototype works fine with the suggestion in their documentation, but not when I install angular-cli@webpack and migrate my prototype to angular-cli@webpack!

@leon
Copy link
Contributor

leon commented Aug 29, 2016

Since d3 split into multiple modules with the V4 release the old typings for < 4 don't work.

you need to install the new typings.

The typings have been split into the different modules

for example

d3-selection has types in the @types/d3-selection npm repository.
d3-shape has types in the @types/d3-shape npm repository....

and the d3 npm package is just a aggregating package
https://github.com/d3/d3/blob/master/package.json#L41

With TypeScript 2 it will automatically find the definition files under the node_modules/@types so you only have to install them using npm and then it will work.

And since angular-cli has switched to webpack and typescript 2 I think this is the recommended way.

@aderbas
Copy link

aderbas commented Aug 29, 2016

@leon I did exactly as the documentation to install the leaflet maps.

$ npm install --save leaflet
$ npm install --save-dev @types/leaflet

I do build but received error

ReferenceError: L is not defined
    at new MapService (http://localhost:4200/main.bundle.js:66441:32)
    at DebugAppView._View_MainViewComponent_Host0.createInternal (MainViewComponent.ngfactory.js:20:26)
    at DebugAppView.AppView.create (http://localhost:4200/main.bundle.js:60438:21)
    at DebugAppView.create (http://localhost:4200/main.bundle.js:60651:44)
    at ComponentFactory.create (http://localhost:4200/main.bundle.js:43429:36)
    at ViewContainerRef_.createComponent (http://localhost:4200/main.bundle.js:43998:45)
    at RouterOutlet.activate (http://localhost:4200/main.bundle.js:51268:40)
    at ActivateRoutes.placeComponentIntoOutlet (http://localhost:4200/main.bundle.js:15482:16)
    at ActivateRoutes.activateRoutes (http://localhost:4200/main.bundle.js:15459:22)
    at http://localhost:4200/main.bundle.js:15421:19

@ghost
Copy link
Author

ghost commented Aug 29, 2016

@leon - I used the following instructions found on the D3 site:

# Installation
> `npm install --save @types/d3`

# Summary
This package contains type definitions for d3JS (http://d3js.org/).

# Details
Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0/d3

Additional Details
 * Last updated: Thu, 25 Aug 2016 16:56:03 GMT
 * File structure: UMD
 * Library Dependencies: none
 * Module Dependencies: none
 * Global values: d3

# Credits
These definitions were written by Alex Ford <https://github.com/gustavderdrache>, Boris Yankov <https://github.com/borisyankov>.

As you can see, these are instruction install all modules. Also, inspecting node_modules/@types/d3 I see all the modules there, including the ones which my app fails on!

@aderbas
Copy link

aderbas commented Aug 29, 2016

@dematic-rodrigo-silveira same here =/
+1

@ckopsa
Copy link

ckopsa commented Aug 29, 2016

I was able to get it working.
@dematic-rodrigo-silveira I did a combination of things, but I feel like the one that did it was upgrading to the most recent typescript. I'm pretty sure this is what I did:

# Get rid of old typescript
npm uninstall typescript
# Get new typescript
npm install typescript@beta --save
# Ensure I have most recent typescript
npm list typescript
# Reinstall d3
npm install --save d3
npm install @types/d3 --save-dev
# Serve it up
ng serve

However, when trying to set the style of a given d3 element the browser console states:
"TypeError: Cannot read property 'style' of null."

I've tried with ViewContainerRef, ElementRef and Renderer with no avail. I feel like the native element is actually null because I don't know how to get it. The Angular2 documentation on ElementRef states nativeElement returns null when having to go through a web worker. I'm not sure how to work around that. Here is the different code I've tried with other options commented out.

import { Directive,
     OnInit,
     Inject,
     ViewContainerRef,
//   ElementRef,
//   Renderer,
     Attribute } from '@angular/core';
import * as d3 from 'd3';

@Directive({
    selector: 'bargraph',
    inputs: ['bardata']
})
export class Bargraph implements OnInit {
    bardata:Array<number>;
    length:number;
    divs: any;
    constructor(
    @Inject(ViewContainerRef) viewContainerRef: ViewContainerRef,
//  @Inject(ElementRef) elementRef: ElementRef,
//  @Inject(Renderer) renderer: Renderer,
    @Attribute('width') width: string,
    @Attribute('height') height: string) {

    var el:any    = viewContainerRef.element.nativeElement;
//  var el:any    = elementRef.nativeElement;
//  var el:any    = renderer.selectRootElement(/* not sure what goes in here */);
    var graph:any = d3.select(el);

    this.divs = graph.
        append('div').
        attr({
        'class': 'chart'
        }).
        style({
        'width':  width  + 'px',
        'height': height + 'px',
        }).on('click', (ev) => this.click(ev)).
        selectAll('div');
    }

    ngOnInit(){
    this.render(this.bardata);
    }

    render(newValue) {
    if (!newValue) return;
    this.divs.data(newValue).enter().append('div')
        .transition().ease('elastic')
        .style('width', d => d + '%')
        .text(d => d + '%');
    }

    click(data)
    {
    alert("div clicked");   
    }
}

@tomwanzek
Copy link

Hi All,

I am going to provide a little context, which might explain some of the encountered experiences and offer a perspective going forward. I'll draw on the fact that I have written the new version 4 definitions for D3 in DefinitelyTyped with much appreciated contributions from @Ledragon, @gustavderdrache and @arrayjam.

The definitions you acquire for use from npm @types require indeed use of TypesScript 2.x. The primary reason is that TS 2 implements the module/definition resolution to support using definitions installed with e.g. npm install @types/d3-selection --save. That is without additional tools like e.g. typings.

As there is a migration process on the way between DefinitelyTyped and @types, the definitions for D3 are also in transition. Currently, the following applies

  • The definitions you acquire with npm install @types/d3 --save are still definitions for version D3 3.5.x
  • For all individual D3 version 4 modules with the exception of d3-dsv and d3-request, there are version 4 compliant definitions in @types, e.g. npm install @types/d3-selection --save will to the trick.

The reason why the standard bundle definitions for D3 v4 itself and definitions for d3-dsv and d3-request have not been migrated yet, has to do with transition process. We are in the process of ensuring within DefinitelyTyped and @types that other libraries which still depend on legacy version definitions will continue to have access to them. More detail can be found on the DefinitelyTyped issue 9936.

Going forward, earlier today I have created a repo for an Angular 2 D3 service. I have also published an initial draft version as an npm package d3-ng2-service.

Between today and tomorrow, I will polish things up a little and also put an angular-cli-based (webpack-beta) project up, which demonstrates the use of the D3Service.

Note that the new definitions also require TypeScript 2, because they use this typing for function contexts (e.g. DOM element binding) and a couple of other new features.

Hopefully, we can resolve the remaining definition transition issues shortly.

P.S. Until the migration of the D3 version 4 definitions is complete, the repo we used for the collaborative development is still active and can be found here: d3-v4-definitelytyped.

@ghost
Copy link
Author

ghost commented Aug 30, 2016

@tom thanks for the thorough explanation and work. I just attempted to follow your instructions and, unfortunately, was unsuccessful. I have a very simple application, it is a POC, of which I'll include the main files here:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, ApplicationRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

import { D3Service } from 'd3-ng2-service';
import {BarGraphDirective} from "./directives/bar-graph.directive"; // <-- import statement

@NgModule({
  declarations: [
    AppComponent,
      BarGraphDirective
  ],
  imports: [
    BrowserModule,
    CommonModule,
    FormsModule
  ],
  providers: [D3Service],
  entryComponents: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

app.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    styleUrls: ['app.component.css'],
    templateUrl: 'app.component.html'
})

export class AppComponent
{
    private graphData: Array<Number>;  // bar graph data (bound to from template)

    /**
     * Create a bar chart demo component
     *
     * @return nothing This is the root component of the demo.
     */
    constructor()
    {
        // assign the chart data and away we go ...
        this.graphData = [10, 20, 30, 40, 60];
    }
}

app.component.html

<div class="container-fluid rounded">
    <div class="row">
        <img class="img-responsive a2d3-logo-img" src="anvil.png">
        <div>
            <span id="algorithmist" class="pull-left">The Continuous Flow User Experience</span>
        </div>
    </div>

    <div class="row a2d3-content">
        <h3 class='a2p-h1'>Template Project - A simple animated bar chart</h3>

        <div class="a2d3-pad-top">
            <bar-graph bind-data="graphData" width="400" height="150" ></bar-graph>
        </div>
    </div>
</div>

bar-graph-directive.ts

import { Directive, ElementRef, Attribute, SimpleChange } from '@angular/core';
import { D3Service, D3, Selection } from 'd3-ng2-service'; // <-- import the D3 Service, the type alias for the d3 variable and the Selection interface

@Directive({
    selector: 'bar-graph',

    properties: ['data'],
})

export class BarGraphDirective
{
    private data: Array<number>;  // raw chart data
    private divs: any;            // DIV collection

    /**
     * Construct a new BarGraph
     *
     * @param elementRef: ElementRef (Injected) Reference to the DOM element associated with this Directive (see selector)
     *
     * @param width: string Width attribute from the containing template
     *
     * @param height: string Height attribute from the containing template
     *
     * @return Nothing
     */
    constructor ( elementRef: ElementRef, d3Service: D3Service, @Attribute('width') width: string, @Attribute('height') height: string )
    {
        let el: any = elementRef.nativeElement;  // reference to <bar-graph> element from the main template
        let d3: D3 = d3Service.getD3(); // <-- obtain the d3 object from the D3 Service
        let graph: Selection<any, any, any, any> = d3.select(el);             // D3 chart container

        // setup the graph
        this.divs = graph
            .append('div')
            .attr({
                'class': 'chart'
            })
            .style({
                'width': width + 'px',
                'height': height + 'px',
            })
            .selectAll('div');
    }

    // Render the D3 Bar Chart
    private __render(newValue: any): void
    {
        if( !newValue )
            return;

        // join the data,then chain styles and bar text ... all the usual suspects
        this.divs.data(newValue).enter().append('div')
            .transition().ease('elastic')
            .style('width', (d:any) => d + '%')
            .text( (d:any) => d + '%');
    }

    // update render on change
    private ngOnChanges( changes: { [propertyName: string]: SimpleChange } ): void
    {
        this.__render( this.data );
    }
}

When I run the app, the following error message is shown:

browser_adapter.js:84EXCEPTION: Error in ./AppComponent class AppComponent - inline template:12:12BrowserDomAdapter.logError @ browser_adapter.js:84BrowserDomAdapter.logGroup @ browser_adapter.js:94ExceptionHandler.call @ exception_handler.js:65(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
browser_adapter.js:84ORIGINAL EXCEPTION: TypeError: Cannot read property 'style' of nullBrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:74(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
browser_adapter.js:84ORIGINAL STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:77(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
browser_adapter.js:84TypeError: Cannot read property 'style' of null
    at new BarGraphDirective (bar-graph.directive.ts:43)
    at DebugAppView._View_AppComponent0.createInternal (AppComponent.ngfactory.js:73)
    at DebugAppView.AppView.create (view.js:101)
    at DebugAppView.create (view.js:314)
    at DebugAppView._View_AppComponent_Host0.createInternal (AppComponent.ngfactory.js:18)
    at DebugAppView.AppView.create (view.js:101)
    at DebugAppView.create (view.js:314)
    at ComponentFactory.create (component_factory.js:156)
    at ApplicationRef_.bootstrap (application_ref.js:516)
    at application_ref.js:374BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:78(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
browser_adapter.js:84ERROR CONTEXT:BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:81(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
browser_adapter.js:84DebugContext {_view: _View_AppComponent0, _nodeIndex: 20, _tplRow: 12, _tplCol: 12}BrowserDomAdapter.logError @ browser_adapter.js:84ExceptionHandler.call @ exception_handler.js:82(anonymous function) @ application_ref.js:267ZoneDelegate.invoke @ zone.js:323onInvoke @ ng_zone_impl.js:53ZoneDelegate.invoke @ zone.js:322Zone.run @ zone.js:216(anonymous function) @ zone.js:571ZoneDelegate.invokeTask @ zone.js:356onInvokeTask @ ng_zone_impl.js:44ZoneDelegate.invokeTask @ zone.js:355Zone.runTask @ zone.js:256drainMicroTaskQueue @ zone.js:474
zone.js:461Unhandled Promise rejection: EXCEPTION: Error in ./AppComponent class AppComponent - inline template:12:12
ORIGINAL EXCEPTION: TypeError: Cannot read property 'style' of null
ORIGINAL STACKTRACE:
TypeError: Cannot read property 'style' of null
    at new BarGraphDirective (http://localhost:4200/main.bundle.js:79889:13)
    at DebugAppView._View_AppComponent0.createInternal (AppComponent.ngfactory.js:73:34)
    at DebugAppView.AppView.create (http://localhost:4200/main.bundle.js:60119:21)
    at DebugAppView.create (http://localhost:4200/main.bundle.js:60332:44)
    at DebugAppView._View_AppComponent_Host0.createInternal (AppComponent.ngfactory.js:18:14)
    at DebugAppView.AppView.create (http://localhost:4200/main.bundle.js:60119:21)
    at DebugAppView.create (http://localhost:4200/main.bundle.js:60332:44)
    at ComponentFactory.create (http://localhost:4200/main.bundle.js:43168:36)
    at ApplicationRef_.bootstrap (http://localhost:4200/main.bundle.js:29258:40)
    at http://localhost:4200/main.bundle.js:29116:89
ERROR CONTEXT:
[object Object] ; Zone: <root> ; Task: Promise.then ; Value: ViewWrappedException {_wrapperMessage: "Error in ./AppComponent class AppComponent - inline template:12:12", _originalException: TypeError: Cannot read property 'style' of null
    at new BarGraphDirective (http://localhost:4200/…, _originalStack: "TypeError: Cannot read property 'style' of null↵  … at http://localhost:4200/main.bundle.js:29116:89", _context: DebugContext, _wrapperStack: "Error: Error in ./AppComponent class AppComponent … at http://localhost:4200/main.bundle.js:29116:89"}consoleError @ zone.js:461_loop_1 @ zone.js:490drainMicroTaskQueue @ zone.js:494
zone.js:463 Error: Uncaught (in promise): EXCEPTION: Error in ./AppComponent class AppComponent - inline template:12:12(…)

package.json

{
  "name": "a2d3-bar",
  "version": "0.0.0",
  "license": "MIT",
  "angular-cli": {},
  "scripts": {
    "start": "ng serve",
    "lint": "tslint \"src/**/*.ts\"",
    "test": "ng test",
    "pree2e": "webdriver-manager update",
    "e2e": "protractor"
  },
  "private": true,
  "dependencies": {
    "@angular/common": "2.0.0-rc.5",
    "@angular/compiler": "2.0.0-rc.5",
    "@angular/core": "2.0.0-rc.5",
    "@angular/forms": "0.3.0",
    "@angular/http": "2.0.0-rc.5",
    "@angular/platform-browser": "2.0.0-rc.5",
    "@angular/platform-browser-dynamic": "2.0.0-rc.5",
    "@angular/router": "3.0.0-rc.1",
    "core-js": "^2.4.0",
    "d3-ng2-service": "^1.0.0",
    "reflect-metadata": "0.1.3",
    "rxjs": "5.0.0-beta.6",
    "ts-helpers": "^1.1.1",
    "zone.js": "0.6.12"
  },
  "devDependencies": {
    "@types/jasmine": "^2.2.30",
    "@types/protractor": "^1.5.16",
    "angular-cli": "1.0.0-beta.11-webpack.2",
    "codelyzer": "0.0.26",
    "jasmine-core": "2.4.1",
    "jasmine-spec-reporter": "2.5.0",
    "karma": "0.13.22",
    "karma-chrome-launcher": "0.2.3",
    "karma-jasmine": "0.3.8",
    "karma-remap-istanbul": "^0.2.1",
    "protractor": "3.3.0",
    "ts-node": "1.2.1",
    "tslint": "3.13.0",
    "typescript": "^2.0.0"
  }
}

@tomwanzek
Copy link

tomwanzek commented Sep 1, 2016

@dematic-rodrigo-silveira My apologies, but currently I do not have the cycles to review the entire code. At a quick cursory glance, I would suggest the following off the top of my head:

  • create a private member to store the d3 variable you get from the D3 Service in the constructor
  • create a private member to store the elementRef.nativeElement in the constructor
  • use the onInit lifecycle hook and move any code from using d3.select onwards to ngOnInit() {...}

Depending on how sophisticated you want to get, you might want to verify that nativeElement is at least not null, before selection and use.

I.e. it might simply be down to a timing thing 😄. In general and as per ususal, stackOverflow might be good place to explore further...

@a5hik
Copy link

a5hik commented Sep 1, 2016

You can use it via the typings

Add this in your typings.d.ts

declare module 'd3' { let exportAs: any; export = exportAs; }

and in your component import it by..

import * as d3 from 'd3';

@tomwanzek
Copy link

@a5hik As angular-cli uses TS2, there is no material need to work without proper definitions for d3 version 4 and simply declare it as any. See my issues comment above.

A proper service can be built from the already published module-level definitions for the separate D3 modules. This includes arbitrary custom subsets of d3, where not all functionality is required, e.g. d3-geo may not be applicable for a given project.

I expect the availability of the two remaining definitions for d3-dsv and d3-request through @types to be resolved shortly as well. I just restructured the PR on DefinitelyTyped that feeds @types.

d3-request should not be an issue to begin with in the context of using Angular 2.

@ghost
Copy link
Author

ghost commented Sep 2, 2016

@a5hik, thanks for the suggestion; at this point it is known that it does not work due to typings issues being flushed out. Fortunately I was able to get it to work following @tomwanzek suggestions above. I still observe method not found errors in my IntelliJ, but things work.

Now, I need to get d3-gauge to work; I followed the instructions on the angular-cli main page regarding Global Libraries, without any luck. Before I close this issue and open a separate one, perhaps some of those who contributed to this issue might be able to help.

@tomwanzek
Copy link

@dematic-rodrigo-silveira can you let me know which method not found errors you still experience? Should they be related to the already published definitions for the D3 v4 modules, I would love to see, if you came across any as yet unknown issue with them.

Just had a quick look at d3-gauge's github repo. It looks like it depends on D3 v~3.3.5, i. e. it does not seem to have been ported to D3v4 yet. Given the breaking changes between versions 3 and 4, seems a project might end up a bit in limbo with D3 v3 and v4 components...

@ghost
Copy link
Author

ghost commented Sep 2, 2016

@tomwanzek , see below for the source code. All 3 d3 references are in red (wrt to liquidgage, c'est la vie, thanks!):

Source code

import {Component, OnInit, Input, Attribute, ElementRef} from '@angular/core';
import {D3Service, D3} from "d3-ng2-service";

// see https://bl.ocks.org/d3noob/bdf28027e0ce70bd132edc64f1dd7ea4 for template
@Component({
    selector: 'new-bar-graph',
    templateUrl: 'new-bar-graph.component.html',
    styleUrls: ['new-bar-graph.component.css']
})
export class NewBarGraphComponent implements OnInit {
    private elementRef: ElementRef;
    private d3Service: D3Service;
    private width: string;
    private height: string;
    private d3: D3;
    private el: ElementRef;

    constructor(elementRef: ElementRef, d3Service: D3Service, @Attribute('width') width: string, @Attribute('height') height: string ) {
        this.elementRef = elementRef;  // reference to <bar-graph> element from the main template
        this.d3Service = d3Service;
        this.width = width;
        this.height = height;

        // Debugging ... working
        console.log("NewBarGraphComponent::constructor elementRef.nativeElement.id: " + this.elementRef.nativeElement.id);
        console.log("NewBarGraphComponent::constructor d3Service: " + (this.d3Service !== null ? "got d3service" : "d3Service not defined"));
        console.log("NewBarGraphComponent::constructor width: " + this.width);
        console.log("NewBarGraphComponent::constructor height: " + this.height);
    }

    @Input() newBarGraphData:  Array<{name: string, sales: number}>;

    ngOnInit() {
        let el: any = this.elementRef.nativeElement;  // reference to <bar-graph> element from the main template
        let d3: D3 = this.d3Service.getD3(); // <-- obtain the d3 object from the D3 Service

        // Debugging ... working
        console.log("NewBarGraphComponent::constructor el.id: " + el.id);
        console.log("NewBarGraphComponent::constructor d3: " + (d3 !== null ? "got d3" : "d3 not defined"));
        console.log("NewBarGraphComponent::constructor data: " + JSON.stringify(this.newBarGraphData));


        // set the dimensions and margins of the graph
        let margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

        // set the ranges
        let x = d3.scaleBand()
            .range([0, width])
            .padding(0.1);
        let y = d3.scaleLinear()
            .range([height, 0]);

        // append the svg object to the body of the page
        // append a 'group' element to 'svg'
        // moves the 'group' element to the top left margin
        let svg = d3.select("#new-bar-graph")
            .append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
            .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        // Scale the range of the data in the domains
        x.domain(this.newBarGraphData.map(function(d) { return d.name; }));
        y.domain([0, d3.max(this.newBarGraphData, function(d) { return d.sales; })]);

        // append the rectangles for the bar chart
        svg.selectAll(".bar")
            .data(this.newBarGraphData)
            .enter().append("rect")
            .attr("class", "bar")
            .attr("x", function(d) { return x(d.name); })
            .attr("width", x.bandwidth())
            .attr("y", function(d) { return y(d.sales); })
            .attr("height", function(d) { return height - y(d.sales); });

        // add the x Axis
        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x));

        // add the y Axis
        svg.append("g")
            .call(d3.axisLeft(y));
    }
}

@tomwanzek
Copy link

Here is a brief update related to D3 in an Angular 2 context:

  • After some fixes to the way definition files are published from DefinitelyTyped/types-2.0 to npm @types, the npm definitions now have version numbers corresponding to the following (slightly adjusted) semver: major.minor.definition, where major and minor correspond to the D3 module version and definition is increased, whenever a new definition is released.
  • All modules contained in the standard D3 bundle have a corresponding definitions file. You will also find a few additional D3 module definitions, which are not part of the standard bundle (e.g. d3-selection-multi)
  • The definitions under @types/d3 are still for version 3.5.x. The TypeScript team has an open item to build support for parallel versions in DefinitelyTyped/types-2.0. (See DT issue 9936). Should you require an idea for a D3 standard bundle definitions file, you can follow the approach here. Just change the relative path re-exports to export * from 'd3-array'; etc, assuming you installed the module-level types from @types.

As next steps on the definitions themselves, there should be some upcoming work to add more JSDoc comments and vetting to enable strictNullChecks. As this work will occur on DefinitelyTyped on a go forward basis, the aforementioned issue 9936 is a good dive-off point.

Specifically, to Angular 2:

  • the convenience D3 service provided by the package d3-ng2-service (npm install d3-ng2-service --save) works with all the latest ng2 release candidates and the recently release final version 2.0.0.
  • thanks to the massively improved angular-cli beta.15 🎉, I have updated the reference demo at d3-ng2-demo. The live version is on the d3-ng2-demo github page. It uses some well-known D3 bl.ocks as a starting point to illustrate key considerations to get started with the D3 Service. Illustrative Karma/Jasmine tests and a suitably illustrative e2e Protractor test are included for your perusal.

Cheers.

@filipesilva
Copy link
Contributor

I appreciate that D3 is a very useful and popular library and that getting it to work with Angular is obviously desirable, but at the moment in this issue there doesn't seem to any CLI specific bugs that can be addressed. For that reason I am closing it.

@alexmac131
Copy link

This ng libs for angular and d3 were written in 2016, it is 2018... What progress has been made, I had to do the import * as d3 from 'd3'; still as the d3-ng2-service Still does not have some key bits to make things work,

@tomwanzek
Copy link

@alexmac131 The typescript definitions for all the standard D3 bundle modules are published on DefinitelyTyped and have been actively maintained since end-of 2016. This includes the definition file for the standard D3 bundle itself, which is a re-export of the constituent modules.

So following the standard approach to importing D3 modules in conjunction with installing the definitions from @types/d3-xxx, gives you full flexibility to create your own D3 service for Angular, should you wish to use it through a service.

You do not have to use d3-ng2-service, if it is not specific enough to your needs. You can simply follow the pattern which was used to create it. All the building blocks are readily available for standard TypeScript imports. d3-ng2-service was never intended to address all use cases of D3, as they are too varied, it tracks the standard D3 module bundle, with the exception of d3-request, which I left out on purpose given the preference for using Angular for client/server-communication.

There are also actively maintained definitions for some "non-standard" D3 modules, e.g. d3-sankey and d3-contour.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jun 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants