Adding D3 chart to InfoWindow Pop Up

8693
10
Jump to solution
05-18-2015 09:50 AM
LisCollins
Occasional Contributor

Hello,

Does anyone have experience using D3 charts with ESRI maps?

I'm having issues getting a D3 chart to show up in my infowindow pop up on my web map.

What I want to happen:

I want my D3 Chart to show up in the custom info window template of my pop up that I created.

Error

-When I click on a county boundary, the D3 graph refuses to show in the info template div I created for my pop up. The result is just blank.

What is working:

The sample D3 graph shows in a random class I created for testing on the left side of the map called "chart".

Also, the sample D3 data variable shows in the pop up though the d3 graph refuses too. I'm using this tutorial to try to make a simple D3 bar chart: Let’s Make a Bar Chart

What I have tried:

I tried using Dojo charts but dojo is very complicated to use for me and there aren't too many tutorials explaining how to use the stacked bar chart. ESRI's native charts do no meet my needs either as eventually I want to use a dynamic stacked column chart. ->Seen here: Stacked Bar Chart

Right now, I'm just testing with a simple D3 bar chart and can't even get that too work.

Code here:

Edit fiddle - JSFiddle - Check out the JSFIddle for the whole code though it's not showing in the re...

JS part

// infotemplate formatting functions need to be in the global scope to work
      var map;
      var showChart;
      var theme = "Wetland";


      require([
        "esri/map",
        "esri/layers/ArcGISDynamicMapServiceLayer",
        
         "esri/dijit/InfoWindow",
        "esri/InfoTemplate",
        "esri/layers/FeatureLayer",
        "esri/renderers/SimpleRenderer",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "dojo/dom",
        "dojo/number",
        "dojo/on",
        "dojo/parser",
        "esri/Color",
        
        
        //charts
        //"dojo/charting/plot2d/StackedColumns",
        "dojox/charting/Chart",
        //"dojox/charting/themes/" + theme,
        "dojox/charting/plot2d/Lines",
        "dojox/charting/plot2d/Columns",
        "dojox/charting/plot2d/StackedColumns",
        "dojox/charting/axis2d/Default",
        "dojo/dom-class",

        
      "esri/tasks/QueryTask",
      "esri/tasks/query",
"esri/symbols/SimpleMarkerSymbol",

        
        
        "dijit/layout/BorderContainer",
        "dijit/layout/ContentPane",
        "dojox/layout/ExpandoPane",
        "dijit/layout/TabContainer",
        "dojox/charting/Chart2D", "dojox/charting/plot2d/Pie", 
        "dojox/charting/action2d/Highlight",
        "dojox/charting/action2d/MoveSlice", "dojox/charting/action2d/Tooltip",
        "dojo/dom-construct", "dojo/number",
        "dojox/charting/themes/" + theme,

        
        "dojo/domReady!"
      ],
        function (
          Map, ArcGISDynamicMapServiceLayer, InfoWindow, InfoTemplate, FeatureLayer, SimpleRenderer, SimpleFillSymbol,
          SimpleLineSymbol, dom, number, on, parser, Color, 
          //dojochart
        Chart, 
        //dojoxTheme,        
        Lines,
        Columns,
        StackedColumns,
        Default,
        domClass,
        
        //for query
        QueryTask, Query, SimpleMarkerSymbol,
        
          BorderContainer,
        ContentPane,
        ExpandoPane,
        TabContainer,
         Chart2D, Pie, 
        Highlight,
        MoveSlice, Tooltip,
        domConstruct, number, dojoxTheme

          
      ) {

          parser.parse();

          // Use the info window instead of the popup.
        var infoWindow = new InfoWindow(null, domConstruct.create("div"));
        infoWindow.startup();

          
//base map, centering, and zooming; add to div
          map = new Map("mapDiv", {
            basemap: "gray",
            center: [-76.796, 38.13],
            zoom: 8
          });

  map.infoWindow.resize(475, 475);
         
var data = [4, 8, 15, 16, 23, 42];


    //the long way
var chart = d3.select(".chart");
var bar = chart.selectAll("div");
var barUpdate = bar.data(data); //join data
var barEnter = barUpdate.enter().append("div");
barEnter.style("width", function(d) { return d * 10 + "px"; });
barEnter.text(function(d) { return d; });
    
    
          //infotemplate
          var infoTemplate = new InfoTemplate();
          infoTemplate.setTitle("County: ${COUNTY}");
          //infoTemplate.setContent("<div id='d3code2' class='d3Pop'> </div>");
          infoTemplate.setContent(getTextContent);
          
         //selects chart container 


d3.select(".d3Pop")
  .selectAll("div")
    .data(data)
  .enter().append("div")
    .style("width", function(d) { return d * 10 + "px"; })
    .text(function(d) { return d; });    

 function getTextContent(graphic) {
 console.log("in get text content function")
        
/*        var body = d3.select(".d3Pop");
          console.log(body);
var div = body.append("div");
console.log(div);
div.html("Hello, world!"); */
var chart = d3.select(".d3Pop1");
var bar = chart.selectAll("div");
var barUpdate = bar.data(data); //join data
console.log(barUpdate);
var barEnter = barUpdate.enter().append("div");
barEnter.style("width", function(d) { return d * 10 + "px"; });
barEnter.text(function(d) { return d; });
console.log(barEnter);    

return "<div class='d3Pop1'>" + bar + data + "</div>";
}

    //add county layer to map
                                  
       var counties = new FeatureLayer("http://geodata.md.gov/imap/rest/services/Boundaries/MD_PoliticalBoundaries/MapServer/1", {
            mode: FeatureLayer.MODE_ONDEMAND,
            infoTemplate: infoTemplate,
            outFields: [
             "COUNTY"
            ]
          });
        
        map.addLayer(counties);
          
        });

HTML

Sorry, I'm having a hard time getting my HTML to display. It won't show in the Jfiddle here either: Edit fiddle - JSFiddle

This is the rest of my HTML code written out that's not in the script tag within <head>

<!DOCTYPE html>

<html>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <!--The viewport meta tag is used to improve the presentation and behavior of the samples

      on iOS devices-->

    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">

    <title>D3 Chart test</title>

    <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dijit/themes/soria/soria.css">

    <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/dojo/dijit/themes/claro/claro.css">

    <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dojox/layout/resources/ExpandoPane.css">

    <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">

    <style>

      html, body { height: 100%; width: 100%; margin: 0; padding: 0; }

  

.chart div, .d3Pop1 div {

  font: 10px sans-serif;

  background-color: steelblue;

  text-align: right;

  padding: 3px;

  margin: 1px;

  color: white;

}

    </style>

<script src="http://d3js.org/d3.v3.min.js"></script>

    <script src="http://js.arcgis.com/3.10/"></script>

</head>

  <body class="soria">

    <div data-dojo-type="dijit/layout/BorderContainer"

         data-dojo-props="design:'headline', gutters:true"

         style="width: 100%; height: 100%; margin: 0;">

      <div data-dojo-type="dojox/layout/ExpandoPane"

           data-dojo-props="duration:300, title:'Details', region:'left', maxWidth:'220px', easeIn:'easing.linear', easeOut:'easing.linear'"

           style="width:220px;">

         <p>

       Click a county to view the population change between 2000 and 2007.<br/> <br/>

          <b>Change the info template:</b> Template 1 displays the percentage growth (or decline) in population. The values are color-coded green for population increase and red for decline in population. Template 2 creates a new calculated field called diff that displays the population difference. <br/>

        </p>

        <div id="d3code" class="chart"></div>

      </div>

      <div id="mapDiv" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">

  

      </div>

    </div>

  </body>

</html>

My Background

-Novice JavaScript Web Developer

-Using ESRI JavaScript 3.10 API and 3.10 CSS

-Test web map template code from ESRI samples

Can anyone figure out why my D3 charts won't display in the popup infowindow template?

Thanks for your help!

0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Lis,

  Here is some working code based on what you have provided (the main thing is that I am creating a div and appending it to the window body, allowing d3 to do it's stuff then passing that node back to the info window setContent):

<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <!--The viewport meta tag is used to improve the presentation and behavior of the samples
      on iOS devices-->
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
  <title>D3 Chart test</title>

  <link rel="stylesheet" href="http://js.arcgis.com/3.13/dijit/themes/soria/soria.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.13/dijit/themes/claro/claro.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dojox/layout/resources/ExpandoPane.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.13/esri/css/esri.css">
  <style>
    html,
    body {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
    }

    .chart div,
    .d3Pop1 div {
      font: 10px sans-serif;
      background-color: steelblue;
      text-align: right;
      padding: 3px;
      margin: 1px;
      color: white;
    }
  </style>

  <script src="http://d3js.org/d3.v3.min.js"></script>
  <script src="http://js.arcgis.com/3.13/"></script>
  <script type="text/javascript">
    // infotemplate formatting functions need to be in the global scope to work
    var map;
    var showChart;
    var theme = "Wetland";


    require([
        "esri/map",
        "esri/layers/ArcGISDynamicMapServiceLayer",
        "esri/dijit/InfoWindow",
        "esri/InfoTemplate",
        "esri/layers/FeatureLayer",
        "esri/renderers/SimpleRenderer",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "dojo/dom",
        "dojo/number",
        "dojo/on",
        "dojo/parser",
        "esri/Color",

        //charts
        //"dojo/charting/plot2d/StackedColumns",
        "dojox/charting/Chart",
        //"dojox/charting/themes/" + theme,
        "dojox/charting/plot2d/Lines",
        "dojox/charting/plot2d/Columns",
        "dojox/charting/plot2d/StackedColumns",
        "dojox/charting/axis2d/Default",
        "dojo/dom-class",
        "dojo/_base/window",

        "esri/tasks/QueryTask",
        "esri/tasks/query",
        "esri/symbols/SimpleMarkerSymbol",

        "dijit/layout/BorderContainer",
        "dijit/layout/ContentPane",
        "dojox/layout/ExpandoPane",
        "dijit/layout/TabContainer",
        "dojox/charting/Chart2D", "dojox/charting/plot2d/Pie",
        "dojox/charting/action2d/Highlight",
        "dojox/charting/action2d/MoveSlice", "dojox/charting/action2d/Tooltip",
        "dojo/dom-construct", "dojo/number",
        "dojox/charting/themes/" + theme,
        "dojo/domReady!"
      ],
      function (
        Map, ArcGISDynamicMapServiceLayer, InfoWindow, InfoTemplate, FeatureLayer, SimpleRenderer, SimpleFillSymbol,
        SimpleLineSymbol, dom, number, on, parser, Color,
        //dojochart
        Chart,
        //dojoxTheme,
        Lines,
        Columns,
        StackedColumns,
        Default,
        domClass,
        win,

        //for query
        QueryTask, Query, SimpleMarkerSymbol,

        BorderContainer,
        ContentPane,
        ExpandoPane,
        TabContainer,
        Chart2D, Pie,
        Highlight,
        MoveSlice, Tooltip,
        domConstruct, number, dojoxTheme
      ) {

        parser.parse();

        // Use the info window instead of the popup.
        var infoWindow = new InfoWindow(null, domConstruct.create("div"));
        infoWindow.startup();


        //base map, centering, and zooming; add to div
        map = new Map("mapDiv", {
          basemap: "gray",
          center: [-76.796, 38.13],
          zoom: 8
        });

        map.infoWindow.resize(475, 475);

        var data = [4, 8, 15, 16, 23, 42];

        //the long way
        var chart = d3.select(".chart");
        var bar = chart.selectAll("div");
        var barUpdate = bar.data(data); //join data
        var barEnter = barUpdate.enter().append("div");
        barEnter.style("width", function (d) {
          return d * 5 + "px";
        });
        barEnter.text(function (d) {
          return d;
        });


        //infotemplate
        var infoTemplate = new InfoTemplate();
        infoTemplate.setTitle("County: ${COUNTY}");
        infoTemplate.setContent(getTextContent);

        function getTextContent(graphic) {
          console.info(graphic);
          var n = domConstruct.place("<div class='d3Pop1'></div>", win.body());
          var chart = d3.select(".d3Pop1");
          var bar = chart.selectAll("div");
          var barUpdate = bar.data(data); //join data
          var barEnter = barUpdate.enter().append("div");
          barEnter.style("width", function (d) {
            return d * 10 + "px";
          });
          barEnter.text(function (d) {
            return d;
          });
          return n;
        }

        //add county layer to map
        var counties = new FeatureLayer("http://geodata.md.gov/imap/rest/services/Boundaries/MD_PoliticalBoundaries/MapServer/1", {
          mode: FeatureLayer.MODE_ONDEMAND,
          infoTemplate: infoTemplate,
          outFields: [
             "COUNTY"
            ]
        });

        map.addLayer(counties);
      });
  </script>
</head>

<body class="soria">
  <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline', gutters:true" style="width: 100%; height: 100%; margin: 0;">
    <div data-dojo-type="dojox/layout/ExpandoPane" data-dojo-props="duration:300, title:'Details', region:'left', maxWidth:'220px', easeIn:'easing.linear', easeOut:'easing.linear'" style="width:230px;">
      <p>
        Click a county to view the population change between 2000 and 2007.
        <br/>
        <br/>
        <b>Change the info template:</b> Template 1 displays the percentage growth (or decline) in population. The values are color-coded green for population increase and red for decline in population. Template 2 creates a new calculated field called diff that displays the population difference.
        <br/>
      </p>
      <div id="d3code" class="chart"></div>
    </div>
    <div id="mapDiv" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">
    </div>
  </div>
</body>

</html>

View solution in original post

10 Replies
RobertScheitlin__GISP
MVP Emeritus

Lis,

   I don't see any code or attachments.

0 Kudos
RickeyFight
MVP Regular Contributor

Lis,

Esri has been working on getting graphs to work with their maps.

Here are some exaples: Bar Chart | Esri Cedar

0 Kudos
LisCollins
Occasional Contributor

Hi Rickey,

The cedar.js file does not offer the stacked column bar chart option that I need.

Example of the type of chart I need is shown here: Stacked Bar Chart

0 Kudos
LisCollins
Occasional Contributor

Hi Robert,

I'm having trouble getting my HTML to show in this post.

I added the JavaScript code that is found within the <script></script> tags in my code. I just copied and pasted the HTML code separately without using the form's insert HTML tool. I also added my JSfiddle link although I couldn't get it to display properly there either.

Hope this helps.

Lis

0 Kudos
thejuskambi
Occasional Contributor III

InfoWindow is not a good place to be show chart. As it is meant to show information about an individual record. Why do you want to use that instead of creating an new tool. Again, the InfoWindow will expose just one record. Do you have all the values to be displayed in single record?

If you still want it. The way to do it is to customize the InfoWindo widget, and update the map.infoWindow with your custom widget at the time of initialize. Extend the InfoWindowBase or InfoWindow whichever you need.

0 Kudos
LisCollins
Occasional Contributor

Are you sure the InfoWindow is bad for charts?

ESRI shows charts being used in the infowindow in many of their examples.

Show query results with a chart | ArcGIS API for JavaScript

Info window with chart | ArcGIS API for JavaScript

Info windows and graphics | Guide | ArcGIS API for JavaScript

0 Kudos
thejuskambi
Occasional Contributor III

The reason I advised, its not a good idea to use InfoWindow, the template is not constant which will parse the graphic.attributes.

As per the examples, they are using a function in place of template string. so the function should return a domNode, which is completely rendered. In your case, you are sending

     "<div class='d3Pop1'>" + bar + data + "</div>"

your are just parsing "bar" and "data" to string. which is the mistake I believe. try to get the html from the 3D chart object and return it instead. I have not used 3D chart, so will not be able to help you there. Also, you are not using the graphic to generate the content. Should try to think it over how/what you want.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Lis,

  Here is some working code based on what you have provided (the main thing is that I am creating a div and appending it to the window body, allowing d3 to do it's stuff then passing that node back to the info window setContent):

<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <!--The viewport meta tag is used to improve the presentation and behavior of the samples
      on iOS devices-->
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
  <title>D3 Chart test</title>

  <link rel="stylesheet" href="http://js.arcgis.com/3.13/dijit/themes/soria/soria.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.13/dijit/themes/claro/claro.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dojox/layout/resources/ExpandoPane.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.13/esri/css/esri.css">
  <style>
    html,
    body {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
    }

    .chart div,
    .d3Pop1 div {
      font: 10px sans-serif;
      background-color: steelblue;
      text-align: right;
      padding: 3px;
      margin: 1px;
      color: white;
    }
  </style>

  <script src="http://d3js.org/d3.v3.min.js"></script>
  <script src="http://js.arcgis.com/3.13/"></script>
  <script type="text/javascript">
    // infotemplate formatting functions need to be in the global scope to work
    var map;
    var showChart;
    var theme = "Wetland";


    require([
        "esri/map",
        "esri/layers/ArcGISDynamicMapServiceLayer",
        "esri/dijit/InfoWindow",
        "esri/InfoTemplate",
        "esri/layers/FeatureLayer",
        "esri/renderers/SimpleRenderer",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "dojo/dom",
        "dojo/number",
        "dojo/on",
        "dojo/parser",
        "esri/Color",

        //charts
        //"dojo/charting/plot2d/StackedColumns",
        "dojox/charting/Chart",
        //"dojox/charting/themes/" + theme,
        "dojox/charting/plot2d/Lines",
        "dojox/charting/plot2d/Columns",
        "dojox/charting/plot2d/StackedColumns",
        "dojox/charting/axis2d/Default",
        "dojo/dom-class",
        "dojo/_base/window",

        "esri/tasks/QueryTask",
        "esri/tasks/query",
        "esri/symbols/SimpleMarkerSymbol",

        "dijit/layout/BorderContainer",
        "dijit/layout/ContentPane",
        "dojox/layout/ExpandoPane",
        "dijit/layout/TabContainer",
        "dojox/charting/Chart2D", "dojox/charting/plot2d/Pie",
        "dojox/charting/action2d/Highlight",
        "dojox/charting/action2d/MoveSlice", "dojox/charting/action2d/Tooltip",
        "dojo/dom-construct", "dojo/number",
        "dojox/charting/themes/" + theme,
        "dojo/domReady!"
      ],
      function (
        Map, ArcGISDynamicMapServiceLayer, InfoWindow, InfoTemplate, FeatureLayer, SimpleRenderer, SimpleFillSymbol,
        SimpleLineSymbol, dom, number, on, parser, Color,
        //dojochart
        Chart,
        //dojoxTheme,
        Lines,
        Columns,
        StackedColumns,
        Default,
        domClass,
        win,

        //for query
        QueryTask, Query, SimpleMarkerSymbol,

        BorderContainer,
        ContentPane,
        ExpandoPane,
        TabContainer,
        Chart2D, Pie,
        Highlight,
        MoveSlice, Tooltip,
        domConstruct, number, dojoxTheme
      ) {

        parser.parse();

        // Use the info window instead of the popup.
        var infoWindow = new InfoWindow(null, domConstruct.create("div"));
        infoWindow.startup();


        //base map, centering, and zooming; add to div
        map = new Map("mapDiv", {
          basemap: "gray",
          center: [-76.796, 38.13],
          zoom: 8
        });

        map.infoWindow.resize(475, 475);

        var data = [4, 8, 15, 16, 23, 42];

        //the long way
        var chart = d3.select(".chart");
        var bar = chart.selectAll("div");
        var barUpdate = bar.data(data); //join data
        var barEnter = barUpdate.enter().append("div");
        barEnter.style("width", function (d) {
          return d * 5 + "px";
        });
        barEnter.text(function (d) {
          return d;
        });


        //infotemplate
        var infoTemplate = new InfoTemplate();
        infoTemplate.setTitle("County: ${COUNTY}");
        infoTemplate.setContent(getTextContent);

        function getTextContent(graphic) {
          console.info(graphic);
          var n = domConstruct.place("<div class='d3Pop1'></div>", win.body());
          var chart = d3.select(".d3Pop1");
          var bar = chart.selectAll("div");
          var barUpdate = bar.data(data); //join data
          var barEnter = barUpdate.enter().append("div");
          barEnter.style("width", function (d) {
            return d * 10 + "px";
          });
          barEnter.text(function (d) {
            return d;
          });
          return n;
        }

        //add county layer to map
        var counties = new FeatureLayer("http://geodata.md.gov/imap/rest/services/Boundaries/MD_PoliticalBoundaries/MapServer/1", {
          mode: FeatureLayer.MODE_ONDEMAND,
          infoTemplate: infoTemplate,
          outFields: [
             "COUNTY"
            ]
        });

        map.addLayer(counties);
      });
  </script>
</head>

<body class="soria">
  <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline', gutters:true" style="width: 100%; height: 100%; margin: 0;">
    <div data-dojo-type="dojox/layout/ExpandoPane" data-dojo-props="duration:300, title:'Details', region:'left', maxWidth:'220px', easeIn:'easing.linear', easeOut:'easing.linear'" style="width:230px;">
      <p>
        Click a county to view the population change between 2000 and 2007.
        <br/>
        <br/>
        <b>Change the info template:</b> Template 1 displays the percentage growth (or decline) in population. The values are color-coded green for population increase and red for decline in population. Template 2 creates a new calculated field called diff that displays the population difference.
        <br/>
      </p>
      <div id="d3code" class="chart"></div>
    </div>
    <div id="mapDiv" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">
    </div>
  </div>
</body>

</html>
LisCollins
Occasional Contributor

Thanks so much Robert!

The test graph is now showing in the pop ups.

Now on to the hard part: getting a stacked bar chart to show for my actual feature layer.

Just wondering, do you why I had to append it to a window body for it to work?

I would like to understand why my previous code didn't work. Thanks!

0 Kudos