简体   繁体   中英

d3 - how to figure out when elements go offscreen?

I'm building a US Map with something like 4000 datapoints on it, and I'd like to do it in d3 if at all possible. I've noticed that rendering these many points at once slows Chrome down somewhat, and grids Firefox to a halt. What I'd like is a redraw() function that does the following:

topRightCorner = [x1,y1]
bottomLeftCorner = [x2,y2]
data = data.filter(function(d) {
    projectedCoordinates = proj(lat,lon)
    return(projectedCoordinates[0] < x1 
      && projectedCoordintes[0] > x2
      && projectedCoordinates[1] < y1
      && projectedCoordinates[1] > y2}

ie keeping only the points that after projection (albersUsa in my case) fall in a visible area. I can't seem to find the projected visible dimensions however. Is this feature available?

One approach:

First you need to define the lat/lng of the map's center (centerLatLng). Let's say it's lat=40.0 and lng=97.0, which is roughly in the middle of the contiguous USA.

You also want to know the dimensions (in pixels) of the visible area, say 600x400.

Then your boundaries can be calculated as follows:

var projectedCenter = proj(40, 97);
x1 = projectedCenter[0] - 300;// 300px is half the width of the visible area
x2 = projectedCenter[0] + 300;
y1 = projectedCenter[1] - 200;// 200px is half the height of the visible area
y2 = projectedCenter[1] + 200;

Note that in this example, unlike in your code snippet, [x1, y1] is topLeftCorner and [x2, y2] is bottomRightCorner . And, the filtering criteria should be more like:

return
  projectedCoordinates[0] >= x1 &&
  projectedCoordintes[0] < x2 &&
  projectedCoordinates[1] >= y1 &&
  projectedCoordinates[1] < y2;

Since I posted, I came up with something that's kind of working, and takes a different approach.

I'm doing everything in the AlbersUsa() projection, which is great for layout since I need Alaska and Hawaii, but less great for coding because it doesn't have an invert() function. I used the normal Albers().invert() and just always drew points on AK and HI because there are relatively few anyway.

First I defined the corners:

    projAlbers.scale(defaultScale * d3.event.scale);
    topLeft = projAlbers.invert([0,0]);
    bottomRight = projAlbers.invert([purewidth,pureheight]);

and then rather than project all the coordinates on every redraw, I compared the inverted coordinates of the box to the true lat/lon:

    allCircles.remove();
        visibleDots = data.filter(function(d) {
            return (
                (d.latitude >=49) ||
                (d.longitude < -130) ||
                (d.latitude < topLeft[1] && d.latitude > bottomRight[1] &&
                d.longitude > topLeft[0] && d.longitude < bottomRight[0])); 
        });

This works - the only thing is, when you get to New England or the Pacific Northwest where the map curves, it doesn't draw all the points because the conic projection doesn't correspond to my veiwport rectangle 1:1. Still figuring that one out.

(>= 49 and < -130 to always draw Hawaii and Alaska, naturally)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM