简体   繁体   中英

Use getCtm() at end of d3 translate event

I have the following function that translates a set of circle objects along a predefined SVG path. Per this post , I am attempting to use the getCTM() function to capture the new position of each circle element after each transition runs on each of the respective elements. However, when the below code is executed, it isn't returning the updated transition after each transform. When I look at the matrix values that the getCTM() function is returning for each element, they are:

SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0}

Each circle moves along the SVG path without a hitch, but I can't figure out why the transform values aren't being returned in the SVGMatrix using the code below. Here is a sample of the data being bound to each circle:

trip_headsign : "Ashmont" trip_id : "31562570" trip_name : "11:05 pm from Alewife to Ashmont - Outbound" vehicle_lat : 42.33035301964327 vehicle_lon : -71.0570772306528 stops : Array[5] 0 : Array[6] 0 : "130" 1 : "70085" 2 : 124 3 : Array 1 4 : 124 5 : 0

    var map = L.map('map').setView([42.365, -71.10], 12),
        svg = d3.select(map.getPanes().overlayPane).append("svg"),
        ashmontG = svg.append("g").attr("class", "leaflet-zoom-hide"),
        inboundG = svg.append("g").attr("class", "leaflet-zoom-hide");

    var transform = d3.geo.transform({point: projectPoint}),
        path = d3.geo.path().projection(transform);

    var track = d3.svg.line()
        .interpolate("linear")
        .x(function(d) {
        return applyLatLngToLayer(d).x
        })
        .y(function(d) {
        return applyLatLngToLayer(d).y
        });

    var ashmontPath = ashmontG.selectAll("path")
        .data([ashmont.features])
        .enter()
        .append("path")
        .style("fill", "none")
        .style("stroke", "black")
        .style("stroke-width", 2)
        .style("opacity", 0.1)
        .attr("d", track)

    var trains = inboundG.selectAll("circle")
    .data(a_live_trains)
    .enter()
    .append("circle")
    .attr("r", 6)
    .style("fill", "blue")
    .attr("class", "train");

        d3.selectAll(".train").each(function(d) {

            //the convertCoords function takes a lat/lng pair bound to the circle element and returns the coordinates in pixels using the leaflet latlngtolayerpoint function

            var x = convertCoords(d).x, 
                y = convertCoords(d).y;

            console.log(x, y);

            for(j=0; j<d.stops.length; j++){

                var matrix, xn, xy;

               d3.select(this).transition()
                .duration(d.stops[j][4]*50)
                .delay(d.stops[j][5]*50)
                .attrTween("transform", pathMove(d.stops[j][3]))
                .each("end", ctm(this))

                function ctm(x) {

                   console.log(x);
                   matrix = x.getCTM();

                    xn = matrix.e + x*matrix.a + y*matrix.c,
                    yn = matrix.f + x*matrix.b + y*matrix.d;

                    console.log(xn, yn)
                }

            }
        })

    function pathMove(path) {
        return function (d, i, a) {
            return function(t) {
                var length = path.node().getTotalLength();
                var p = path.node().getPointAtLength(t*length);
                //var ptoPoint = map.layerPointToLatLng(new L.Point(p.x, p.y

                return "translate(" + p.x + "," + p.y + ")";

            }
        }
    }

    moveTrains();

    map.on("viewreset", reset);

    reset();

    function reset() {

        svg.attr("width", bottomRight[0] - topLeft[0] + padding)
            .attr("height", bottomRight[1] - topLeft[1] + padding)
            .style("left", (topLeft[0]-(padding/2)) + "px")
            .style("top", (topLeft[1]-(padding/2)) + "px");

        ashmontG.attr("transform", "translate(" + (-topLeft[0] + (padding/2)) + "," 
                                          + (-topLeft[1] + (padding/2)) + ")");
        inboundG.attr("transform", "translate(" + (-topLeft[0] + (padding/2)) + "," 
                                          + (-topLeft[1] + (padding/2)) + ")");

        ashmontPath.attr("d", track);}

    function projectPoint(x, y) {
        var point = map.latLngToLayerPoint(new L.LatLng(y, x))
        //var point = latLngToPoint(new L.LatLng(y, x));
        this.stream.point(point.x, point.y)
    }

Writing the code as shown immediately below returns the pre-transformation svg matrix. I believe this is happening because the 'this' keyword for each circle object was being selected pre-transform, and was passing the pre-transform SVG position into the ctm function. Additionally, the ctm function was executing before the pathMove function was even being called.

            d3.select(this).transition()
            .duration(d.stops[j][4]*50)
            .delay(d.stops[j][5]*50)
            .attrTween("transform", pathMove(d.stops[j][3]))
            .each("end", ctm(this))

            function ctm(x) {

               console.log(x);
               matrix = x.getCTM();

Slightly modifying the code using the example Mark provided above executes properly. I believe this is due to the fact that the 'this' keyword is being called a second time post-transform within the ctm function. Writing it this way grabs the SVGmatrix each time after the pathMove function has been called.

                d3.select(this).transition()
                .duration(d.stops[j][4]*50)
                .delay(d.stops[j][5]*50)
                .attrTween("transform", pathMove(d.stops[j][3]))
                .each("end", ctm);

                function ctm(x) {

                   console.log(this);
                   matrix = this.getCTM();

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