0

I have an application where a csv file is filtered and the filtered data is displayed on a leaflet map. What I would like to happen is for the map to zoom in to the points. I have tried using fitBounds() but I am unable to identify the points boundary (getBounds() is throwing an error saying it is not a function). I have tried creating a featureGroup but I am still getting the same error.

Here is the relevant code:

    function mapData() {var points = [];        
    var pointsOverlay = L.d3SvgOverlay(function(sel,proj){
    var pointsUpd = sel.selectAll('circle').data(points);       
    pointsUpd.enter()
        .append('circle')
        .attr('cx',function(d){return proj.latLngToLayerPoint(d.latLng).x;})
        .attr('cy',function(d){return proj.latLngToLayerPoint(d.latLng).y;})
        .attr('class', function(d){
            return "point";
        })

        .on('click', function(d){
            tooltip.style("visibility", "visible");
            tooltip.html(
                'JOB NUMBER: ' + '<a href= "https://nycdob.github.io/DOB_NOW_Milestone_App/index_property#' + d.key_id +'" target="_parent">' + d.jobNum + "</a>" + '</br>' +
                'BIN: ' + d.bin + '</br>' +                             
                'ADDRESS: '+ d.HouseNum + ' ' + d.Street + ', ' + d.Borough + '</br>' +
                'COMMUNITY DISTRICT: ' + d.CD + '</br>' +
                'WORK TYPE: '+ d.workType               
            )
            if (d3.event.pageX > (width - 200)) {
               tooltip.style("left", (d3.event.pageX - 350) + "px");
            } else {
               tooltip.style("left", (d3.event.pageX + 20) + "px")
                    .style("top", (d3.event.pageY -30) + "px");
            }
            if (d3.event.pageY > (height - 150)) {
               tooltip.style("top", (d3.event.pageY -100) + "px");
            } else {
               tooltip.style("top", (d3.event.pageY -30) + "px");
            }               
        })
        .on("mouseover", function(d, i){
            tooltip.transition().duration(0); 
            $(this).attr("style", "cursor: pointer; fill: #eef442; fill-opacity: 1;");          
        })
        .on("mouseout", function(d, i){         
            $(this).attr("style", "stroke-width: 0px; fill-opacity: .7;");
            return tooltip.transition().delay(500).style("visibility", "hidden"); 
        });
        pointsUpd.attr('r', 4 / proj.scale);


});

    d3.csv("milestone.csv",function(data){
                var filteredData = data.filter(function(d){
                    if($('#citywide').is(":checked")){
                        return d["Work Type Name"] == workTypeValue
                    } else if ($('input[type=checkbox]:checked').length > 0){
                        return d["Work Type Name"] == workTypeValue && [d.Borough] == boroValue;
                    } else{
                        return d["Work Type Name"] == workTypeValue && d["Community Board"] == Number(cdValue)
                    }
                })
                points = filteredData.map(function(d){
                d.latLng = [+d.Latitude,+d.Longitude];
                d.bin = [d.Bin];                
                d.HouseNum = d["House Number"];
                d.Street = d["Street Name"];
                d.CD = d["Community Board"];
                d.Borough = [d.Borough];
                d.jobNum = d["Job Number"];
                d.workType = d["Work Type Name"];
                d.key_id = [d.key_id];
            return d;
            });         
        pointsOverlay.addTo(map);

        //the below throws an error "pointsOverlay.getBounds() is not a function"
        map.fitBounds(pointsOverlay.getBounds());                       
    });
    map.on('resize', function(){
        map.invalidateSize();
    }); 
}
0

I solved this using the suggestion from TomazicM. I created an array of Lat/Longs from the csv and then create a polyline from the array. I can then get getBounds() from the polyline. I set the opacity of the polyline to zero so it is invisible.

        latLngs = filteredData.map(function(d){             
            return d.latLng;
        });

        pointsOverlay.addTo(map);
        zoom();
        function zoom(){
            if (latLngs === undefined || latLngs == 0){
                window.alert("No results found. Please adjust query criteria");
            }
            else
            {
                var polyline = L.polyline(latLngs,{opacity:0}).addTo(map);
                map.fitBounds(polyline.getBounds());                
            }
        };
|improve this answer|||||
0

Most likely pointsOverlay layer is not ready yet when you try to get bounds with pointsOverlay.getBounds() because milestone.csv is not processed yet.

Try using layer after milestone.csv has finished loading (this is for D3 v3):

d3.csv("milestone.csv",
  function(data){
     ...
     ...
     ...
  },
  function(error, rows) {
    pointsOverlay.addTo(map);
    map.fitBounds(pointsOverlay.getBounds());                       
  }
);

EDIT: Only now I noticed you are using L.D3SvgOverlay plugin (even though you have it in the title of your question :-). This plugin gives SVG image layer and this layer does not have getBounds() method.

EDIT2: After some experimenting I found a way to get bounds of D3SvgOverlay layer:

pointsOverlay.addTo(map);
var bBox = pointsOverlay.selection[0][0].getBBox();
var corner1 = pointsOverlay.projection.layerPointToLatLng([bBox.x, bBox.y]);
var corner2 = pointsOverlay.projection.layerPointToLatLng([bBox.x + bBox.width, bBox.y + bBox.height]);
map.fitBounds(L.latLngBounds(corner1, corner2));
|improve this answer|||||
  • Thanks for your comment. I get an error "d3.csv(...).then is not a function". I should clarify that I'm using D3 v3. Also, all the filtered points load it's just not zooming in to the area. – bmancell Apr 1 '19 at 14:25
  • The call to pointsOverlay.getBounds() has to be after all the points have been processed. In the case of D3 v3 syntax is a bit different, see d3-wiki.readthedocs.io/zh_CN/master/CSV. I updated the answer accordingly. – TomazicM Apr 1 '19 at 15:28
  • Thanks. I updated my code as you suggested but unfortunately I am still getting the error message "pointsOverlay.getBounds is not a function". – bmancell Apr 1 '19 at 15:47
  • Only now I noticed you are using L.D3SvgOverlay plugin, which gives image overlay, not vector overlay. Image overlay does not have getBounds() method. Answer edited. – TomazicM Apr 1 '19 at 16:41
  • Yeah I was afraid of that. Is there a way to zoom-in to an L.D3SvgOverlay? – bmancell Apr 1 '19 at 16:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.