Domanda

I am trying to draw flightpaths on a map using SVGs. I'm using d3 on top of Leaflet, but the frameworks used shouldn't make a difference to my problem - it's trig.

http://fiddle.jshell.net/zw8TR/26

The way I'm trying to do this is by creating a quadratic bezier curve (I'm open to other/easier ways if you know of any). What I need to calculate is 1 control point, perpendicular to the midpoint of each line. This point should always bias to a higher y value / latitude than the midpoint, to create an arc which looks like a flightpath.

In my demo above, I found it's easier to debug exactly where the control point is by adding some extra temporary points. As you can see, some of my control points are facing downwards, and none look to be properly perpendicular.

Check out my previous question on this - with diagrams!

I have a feeling the problem boils down to this line:

var theta = Math.atan2(t_area_y, t_area_x) * 180 / Math.PI;

I'm not handling negative coordinates properly. I have tried to hack in a nasty set of if gates to handle this.

I have tried to comment the fiddle nicely to explain what's going on. Once I know the point, it should be a simple case of creating a custom interpolation in d3.

È stato utile?

Soluzione

This is actually easier than you think if you use a custom line generator. Instead of adding the control points to the feature, you just add them during the computation of the path. The code looks like this:

feature.attr("d", function(d) {
    var s, prev;
    d.geometry.coordinates.forEach(function(c) {
        var proj = map.latLngToLayerPoint(new L.LatLng(c[1], c[0]));
        if(s) {
            var length = Math.sqrt(Math.pow(proj.x - prev.x, 2), Math.pow(proj.y - prev.y, 2)),
                midx = prev.x + (proj.x - prev.x) / 2,
                midy = prev.y + (proj.y - prev.y) / 2 - length * 0.2 * (Math.abs(proj.x - prev.x) / length);
            s += "Q" + midx + "," + midy + " " + proj.x + "," + proj.y;
        } else {
            s = "M" + proj.x + "," + proj.y;
        }
        prev = proj;
    });
    return s;
});

Let's go through it step by step. The main thing is that I'm keeping track of the coordinates of the previous point to be able to compute the control point. First, s will be null and the else branch is taken -- simply move to that point (the start point) without drawing a line. For all subsequent points, the actual computation takes place.

First, we compute the distance between the two points (previous and current), length. Computing the x coordinate of the control point is straightforward, as no offset is required. The y coordinate is a bit trickier -- the first part is the same, then the offset is added. The size of the offset is 20% of the length of the path here (to make wider arcs for longer paths), adjust as necessary. This needs to be multiplied by the cosine of the angle to the x axis, but fortunately we don't need to compute the angle explicitly -- it is defined by the relation between the distance between the points and the difference in x coordinates (the arc cosine of that angle). So we can just take that relation directly and multiply by it. As you want arcs to point up (i.e. negative y offset), we're taking the absolute value of the x coordinate differences. Without that, some of the control points would be pointing down.

Complete example here.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top