redshift
redshift

Reputation: 5237

Why is the D3 chart not appearing in my LeafletJS popups?

Can someone tell me why my d3 chart is not appearing in my popups? Full jsfiddle here. .

The dataset shown for my popups is hypothetical for now, just trying to test and make sure I can get the basics working.

here's my code:

var onEachFeature = function onEachFeature(feature,layer){

var div = $('<div id="chart"><h3>Ethnic Group Distribution</h3><svg/></div>')[0];
var popup = L.popup().setContent(div);

layer.bindPopup(popup);

//Width and height
        var w = 400;
        var h = 300;
        var barPadding = 1;

        var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                        11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

        //Create SVG element
        var svg = d3.select("chart")
                    .append("svg")
                    .attr("width", w)
                    .attr("height", h);

        svg.selectAll("rect")
           .data(dataset)
           .enter()
           .append("rect")
           .attr("x", function(d, i) {
                return i * (w / dataset.length);
           })
           .attr("y", function(d) {
                return h - (d * 4);
           })
           .attr("width", w / dataset.length - barPadding)
           .attr("height", function(d) {
                return d * 4;
           });
};

L.geoJson(afghanDistricts, {
    onEachFeature: onEachFeature
}).addTo(map);

Upvotes: 1

Views: 339

Answers (2)

iH8
iH8

Reputation: 28688

You don't need jQuery to compile the popup's content string to DOM, L.Popup's setContent method already does that for you:

setContent( <String|HTMLElement> htmlContent )

Sets the HTML content of the popup.

http://leafletjs.com/reference.html#popup-setcontent

You can't initialize the chart when the popup isn't open. The content div element will only be attached to the DOM when the popup is open. It gets removed again the popup closes. So you'll need to initialize the chart everytime the popup opens. You can do that by using the popupopen event of your map instance:

L.mapbox.map(...).on('popupopen', function () {
    // Do stuff 
});

Fired when a popup is opened (using openPopup method).

http://leafletjs.com/reference.html#map-popupopen

When using D3's select method to fetch an element by unique identifier, you'll need to prefix a # character:

D3.selector('#chart')

For example, you can select by tag ("div"), class (".awesome"), unique identifier ("#foo"), attribute ("[color=red]"), or containment ("parent child").

https://github.com/mbostock/d3/wiki/Selections

Also you don't need to add an svg element in the content since you're already appending a new svg element: .append("svg"). That creates a new svg element and appends it.

Here's a working snippet:

var afghanDistricts = {"type":"FeatureCollection","features":[{"type":"Feature","properties":{"stroke":"#555555","stroke-width":2,"stroke-opacity":1,"fill":"#555555","fill-opacity":0.5,"Pashtun":0.43,"Tajik":0.12,"Uzbek":0.05,"Turkmen":"0.00","Hazara":"0.00","District":"Argo","Province":"Kandahar"},"geometry":{"type":"Polygon","coordinates":[[[61.69921875,32.08257455954592],[61.69921875,32.879587173066305],[62.666015625,32.879587173066305],[62.666015625,32.08257455954592],[61.69921875,32.08257455954592]]]}},{"type":"Feature","properties":{"Pashtun":0.32,"Tajik":"0.20","Uzbek":0.01,"Turkmen":0.02,"Hazara":"0.00","District":"Jurm","Province":"Farah"},"geometry":{"type":"Polygon","coordinates":[[[62.75390625,32.95336814579932],[62.75390625,33.76088200086917],[63.69873046874999,33.76088200086917],[63.69873046874999,32.95336814579932],[62.75390625,32.95336814579932]]]}},{"type":"Feature","properties":{"Pashtun":0.05,"Tajik":"0.50","Uzbek":0.21,"Turkmen":"0.00","Hazara":"0.00","District":"Ragh","Province":"Ghor"},"geometry":{"type":"Polygon","coordinates":[[[63.74267578125,33.54139466898275],[63.74267578125,34.43409789359469],[65.14892578125,34.43409789359469],[65.14892578125,33.54139466898275],[63.74267578125,33.54139466898275]]]}},{"type":"Feature","properties":{"Pashtun":"0.00","Tajik":0.01,"Uzbek":"0.10","Turkmen":"0.20","Hazara":"0.40","District":"Highan","Province":"Kabul"},"geometry":{"type":"Polygon","coordinates":[[[64.53369140625,35.15584570226544],[64.53369140625,35.94243575255426],[65.56640625,35.94243575255426],[65.56640625,35.15584570226544],[64.53369140625,35.15584570226544]]]}},{"type":"Feature","properties":{"Pashtun":"0.00","Tajik":0.01,"Uzbek":"0.20","Turkmen":"0.30","Hazara":0.04,"District":"Nusay","Province":"Kunduz"},"geometry":{"type":"Polygon","coordinates":[[[65.58837890625,33.30298618122413],[65.58837890625,34.32529192442733],[66.90673828125,34.32529192442733],[66.90673828125,33.30298618122413],[65.58837890625,33.30298618122413]]]}},{"type":"Feature","properties":{"Pashtun":"0.20","Tajik":"0.00","Uzbek":"0.00","Turkmen":"0.10","Hazara":"0.20","District":"Zebak","Province":"Logar"},"geometry":{"type":"Polygon","coordinates":[[[65.98388671875,34.72355492704219],[65.98388671875,35.53222622770337],[66.95068359374999,35.53222622770337],[66.95068359374999,34.72355492704219],[65.98388671875,34.72355492704219]]]}},{"type":"Feature","properties":{"Pashtun":"0.10","Tajik":"0.10","Uzbek":0.28,"Turkmen":"0.10","Hazara":"0.00","District":"Wakhan","Province":"Nimruz"},"geometry":{"type":"Polygon","coordinates":[[[67.32421875,34.43409789359469],[67.32421875,35.42486791930558],[68.37890625,35.42486791930558],[68.37890625,34.43409789359469],[67.32421875,34.43409789359469]]]}}]}

L.mapbox.accessToken = 'pk.eyJ1IjoiZG9zcyIsImEiOiI1NFItUWs4In0.-9qpbOfE3jC68WDUQA1Akg';

var map = L.mapbox.map('mapbox', null, {
  'center': [0, 0],
  'zoom': 0
}).on('popupopen', function () {

  var w = 400;
  var h = 300;
  var barPadding = 1;
  var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13, 11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

  var svg = d3.select("#chart")
  	.append("svg")
  	  .attr("width", w)
  	  .attr("height", h);

  svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
      .attr("x", function(d, i) {
        return i * (w / dataset.length);
    })
    .attr("y", function(d) {
      return h - (d * 4);
    })
    .attr("width", w / dataset.length - barPadding)
      .attr("height", function(d) {
        return d * 4;
    });

});

var geojson = new L.GeoJSON(afghanDistricts, {
	onEachFeature: function (feature, layer) {
		layer.bindPopup(new L.popup().setContent('<div id="chart"><h3>Ethnic Group Distribution</h3></div>'));
	}
}).addTo(map);

map.fitBounds(geojson.getBounds());
body {
    margin: 0;
    padding: 0;
}

#mapbox {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 100%;
    height: 500px;
}
<html>
  <head>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <link type="text/css" rel="stylesheet" href="//api.mapbox.com/mapbox.js/v2.3.0/mapbox.css" />
    <script type="application/javascript" src="//api.mapbox.com/mapbox.js/v2.3.0/mapbox.js"></script>
    <script type="application/javascript" src="//d3js.org/d3.v3.min.js"></script>
  </head>
  <body>
    <div id="mapbox"></div>
  </body>
</html>

Upvotes: 1

Cyril Cherian
Cyril Cherian

Reputation: 32327

Instead of doing:

    var svg = d3.select("chart")//not work because chart is not bound to the DOM
                .append("svg")
                .attr("width", w)

do this:

        var svg = d3.select(div)//the div which holds the tooltip
                    .append("svg")

working code here

Upvotes: 1

Related Questions