Search code examples
javascriptangulardc.jscrossfilter

How to put dc.js and crossfilter.js html page in a Angular component?


I'm trying to put a pie chart into an Angular component. I have built this piechart in a separate HTML file but now I would like to get this HTML into a Single Page Application.

<html>
<head>
    <title></title>
    <base href="/">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="css/dc.css">
    <link rel="stylesheet" type="text/css" href="css/bootstrap.css">
    <link rel="stylesheet" href="css/jquery.dataTables.min.css">
    <link rel="stylesheet" type="text/css" href="css/main.css">
    <link rel="stylesheet" href="./css/keen-dashboards.css">
    <link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body>
<!-- code to display -->
<div class="col-xs-2 pie-chart">
    <h4>Cold vs Active <small><a id="day">reset</a></small></h4>
    <div class="dc-chart" id="chart-ring-tier"></div>
</div>

<script src="js/d3.js"></script>
<script src="js/crossfilter.js"></script>
<script src="js/dc.js"></script>
<script src="js/jquery.dataTables.min.js"></script>
<script src='js/queue.js' type='text/javascript'></script>
<script src="node_modules/keen-dataviz/dist/keen-dataviz.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>

<script type="text/javascript">
            
    System.import('./app/app.module')
        .then(null, console.error.bind(console));
    
    // Fetch data from the api
    queue()
        .defer(d3.json, "http://localhost:3001/api/")
        .await(makeGraphs);

    function makeGraphs(error, apiData) {

        // Parse JSON file, create charts
        var dataSet = apiData.todos;
        
        // Set crossfilter data
        var ndx = crossfilter(dataSet);
        
        var dirnameDim = ndx.dimension(function (d) { return d.dirName });
        var statusDim = ndx.dimension(function (d) { return d.status });
        var all = ndx.groupAll();

        // Create groups (y-axis values)
        var countPerDir = dirnameDim.filterExact("Folder1").group().reduceSum(function(d) { return d.size; });
        var countPerTier = statusDim.group().reduceCount();
            
        // Specify charts
        var tierChart = dc.pieChart('#chart-ring-tier');
            
        tierChart
            .width(150)
            .height(150)
            //.slicesCap(4)
            .innerRadius(20)
            .dimension(statusDim)
            .label(function (d) {
                if (tierChart.hasFilter() && !tierChart.hasFilter(d.key)) {
                    return d.key + '(0%)';
                }
                var label = d.key;
                if (all.value()) {
                    label += '(' + Math.floor(d.value / all.value() * 100) + '%)';
                }
                return label;
            })
            .group(countPerTier);
            
        // Showtime!
        dc.renderAll();
    }
</script>
</body>
</html>

So here is my component.ts. What should I do to render the chart with the component?

And how can I turn the javascript code into TypeScript?

component.ts

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

@Component({
  selector: 'app-group',
  templateUrl: './group.component.html',
  styleUrls: ['./group.component.css']
})
export class GroupComponent implements OnInit {
  constructor() { }

  ngOnInit() {}
}

component.html

<div class="col-xs-2 pie-chart">
    <h4>Cold vs Active <small><a id="day">reset</a></small></h4>
    <div class="dc-chart" id="chart-ring-tier"></div>
</div>

Does anyone have a idea how to realize this?


Solution

  • It requires a bit of work to make it work properly and with the best practices of Angular.

    To use these libraries with TypeScript you need to find d.ts (typed) files for them. I've found them here: https://microsoft.github.io/TypeSearch/

    Then you need to import them to GroupComponent via:

    import * as yourPreferedName from 'your-library';
    

    It should look something like this:

    import * as d3 from 'd3';
    import * as crossfilter from 'crossfilter2';
    import { DSVRowString } from 'd3';
    import * as dc from 'dc';
    

    When you import all d.ts. libraries to the component you need to move all js code to it. Below is short version of GroupComponent which is just an example cause I didn't move code there.

    export class GroupComponent implements OnInit {
    
        constructor() { 
    
        }
    
        ngOnInit() {
             queue().defer(d3.json, "http://localhost:3001/api/")
                    .await(this.makeGraphs);
        }
    
        makeGraphs(error, apiData){
            // Move all your js code here and correct it to the typescript rules
        }
    
    }
    

    If you have any questions feel free to ask me in the comments.