简体   繁体   English

使用传单在d3中沿路径的不正确过渡

[英]Improper transition along path in d3 with leaflet

With the help of d3 v3, i'm trying to create plane animations over leaflet osm map. 在d3 v3的帮助下,我试图在传单osm地图上创建平面动画。 These are the codes i'm using to rotate and move plane element over path between 2 locations. 这些是我用来旋转并在2个位置之间的路径上移动平面元素的代码。 Planes are moving along path but they are not in proper alignment. 飞机沿着路径移动,但它们没有正确对齐。 Here is the complete code : 这是完整的代码:

 var defaultlocation = [28.6139, 77.2090]; var defaultzoom = 5; var map = L.map('map', { center: defaultlocation, // default map location // zoom: defaultzoom, minZoom: 2 }); var mbAttr = '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> Contributors', mbUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; var mapTileLayer = L.tileLayer(mbUrl, { attribution: mbAttr }); map.addLayer(mapTileLayer); map._initPathRoot(); var w = $("#map").innerWidth(); var h = $("#map").innerHeight(); var svg = d3.select(map.getPanes().overlayPane).select(".leaflet-zoom-animated"); var cords = [{ id: 1, lat: 28.6139, lon: 77.2090 }, { id: 2, lat: 19.0760, lon: 72.8777 }]; var links = [{ source: 1, target: 2 }]; for (var i in cords) { cords[i].LatLng = new L.LatLng(cords[i].lat, cords[i].lon); } var linkgroup = svg.selectAll(".linkgroup") .data(links) .enter().append("g") .attr("class", "linkgroup"); var planes = linkgroup.append("path") .attr("class", "plane") .attr("visibility", "hidden") .attr("d", "m25.21488,3.93375c-0.44355,0 -0.84275,0.18332 -1.17933,0.51592c-0.33397,0.33267 -0.61055,0.80884 -0.84275,1.40377c-0.45922,1.18911 -0.74362,2.85964 -0.89755,4.86085c-0.15655,1.99729 -0.18263,4.32223 -0.11741,6.81118c-5.51835,2.26427 -16.7116,6.93857 -17.60916,7.98223c-1.19759,1.38937 -0.81143,2.98095 -0.32874,4.03902l18.39971,-3.74549c0.38616,4.88048 0.94192,9.7138 1.42461,13.50099c-1.80032,0.52703 -5.1609,1.56679 -5.85232,2.21255c-0.95496,0.88711 -0.95496,3.75718 -0.95496,3.75718l7.53,-0.61316c0.17743,1.23545 0.28701,1.95767 0.28701,1.95767l0.01304,0.06557l0.06002,0l0.13829,0l0.0574,0l0.01043,-0.06557c0,0 0.11218,-0.72222 0.28961,-1.95767l7.53164,0.61316c0,0 0,-2.87006 -0.95496,-3.75718c-0.69044,-0.64577 -4.05363,-1.68813 -5.85133,-2.21516c0.48009,-3.77545 1.03061,-8.58921 1.42198,-13.45404l18.18207,3.70115c0.48009,-1.05806 0.86881,-2.64965 -0.32617,-4.03902c-0.88969,-1.03062 -11.81147,-5.60054 -17.39409,-7.89352c0.06524,-2.52287 0.04175,-4.88024 -0.1148,-6.89989l0,-0.00476c-0.15655,-1.99844 -0.44094,-3.6683 -0.90277,-4.8561c-0.22699,-0.59493 -0.50356,-1.07111 -0.83754,-1.40377c-0.33658,-0.3326 -0.73578,-0.51592 -1.18194,-0.51592l0,0l-0.00001,0l0,0z"); var linkpath = linkgroup.append('path') .attr("class", "linkpath") .style("fill", "none"); var markergroup = svg.selectAll(".markergroup") .data(cords) .enter().append("g") .attr("class", "markergroup") .attr("cursor", "pointer") .on("mousedown", function(d) { console.log(d); }); var markercircle = markergroup.append("circle") .attr("class", "markercircle") .on("mousedown", function(d) { console.log(d); }); function getcordsbyid(id) { for (var i in cords) { if (cords[i].id == id) { return cords[i].LatLng; } } } map.on("viewreset", update); update(); fly(1, 2, true); function transition(plane, route, nonstop) { var l = route.node().getTotalLength(); plane.attr("visibility", "visible"); plane.transition() .duration(l * 30) .attrTween("transform", delta(plane, route.node())) .each("end", function() { if (nonstop) { transition(plane, route, nonstop); } else { plane.attr("visibility", "hidden"); } }); } function delta(plane, path) { return function(i) { return function(t) { var l = path.getTotalLength(); var p = path.getPointAtLength(t * l); var t2 = Math.min(t + 0.05, 1); var p2 = path.getPointAtLength(t2 * l); var x = p2.x - px; var y = p2.y - py; var r = 90 - Math.atan2(-y, x) * 180 / Math.PI; var s = Math.min(Math.sin(Math.PI * t) * 0.7, 0.5); return "translate(" + px + "," + py + ") scale(" + s + ") rotate(" + r + ")"; } } } function fly(sourceid, targetid, nonstop) { linkgroup.filter(function(l) { if (l.source == sourceid && l.target == targetid) { return l; } }).each(function(l) { var route = d3.select(this).select(".linkpath"); var plane = d3.select(this).select(".plane"); transition(plane, route, nonstop); }); } function update() { markergroup.attr("transform", function(d) { var cor = map.latLngToLayerPoint(d.LatLng); return "translate(" + cor.x + "," + cor.y + ")"; }); linkgroup.each(function(d, i) { var route = d3.select(this).select(".linkpath").attr("d", function(l) { var slatlong = map.latLngToLayerPoint(getcordsbyid(l.source)); var tlatlong = map.latLngToLayerPoint(getcordsbyid(l.target)); var dx = tlatlong.x - slatlong.x, dy = tlatlong.y - slatlong.y, dr = Math.sqrt(dx * dx + dy * dy) * 3; return "M" + slatlong.x + "," + slatlong.y + "A" + dr + "," + dr + " 0 0,1 " + tlatlong.x + "," + tlatlong.y; }); }); } 
 html, body, #map { width: 100%; height: 100%; } .linkpath { stroke: #FF2EB9; stroke-dasharray: 10, 10; stroke-width: 2 } .markercircle { stroke: black; fill: green; r: 5; cursor: pointer; } .plane { stroke: black; stroke-width: 3; fill: white; } 
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id='map'></div> 

Is there any fault in the delta() or it is because i'm not using geojson path? delta()中是否有任何错误,或者是因为我没有使用geojson路径?

Right now the animation is correct: if you look at the tip of the plane's left wing, it's right over the pink line. 现在动画是正确的:如果你看看飞机左翼的尖端,它就在粉红色的线上。

The problem, therefore, is that you are not taking into account the size of the plane's <path> element itself. 这个问题,因此,是你没有考虑到这架飞机的规模 <path>元素本身。

A simple solution is getting its width: 一个简单的解决方案是获得宽度:

var planesSize = planes.node().getBBox().width; 

And changing the return of the delta function: 并更改delta函数的返回值:

return "translate(" + (p.x + (planesSize / 2 * s)) + 
    "," + (p.y + (planesSize / 2 * s)) + ") scale(" + s + ") rotate(" + r + ")";

Here is the code with those changes: 以下是包含这些更改的代码:

 var defaultlocation = [28.6139, 77.2090]; var defaultzoom = 5; var map = L.map('map', { center: defaultlocation, // default map location // zoom: defaultzoom, minZoom: 2 }); var mbAttr = '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> Contributors', mbUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; var mapTileLayer = L.tileLayer(mbUrl, { attribution: mbAttr }); map.addLayer(mapTileLayer); map._initPathRoot(); var w = $("#map").innerWidth(); var h = $("#map").innerHeight(); var svg = d3.select(map.getPanes().overlayPane).select(".leaflet-zoom-animated"); var cords = [{ id: 1, lat: 28.6139, lon: 77.2090 }, { id: 2, lat: 19.0760, lon: 72.8777 }]; var links = [{ source: 1, target: 2 }]; for (var i in cords) { cords[i].LatLng = new L.LatLng(cords[i].lat, cords[i].lon); } var linkgroup = svg.selectAll(".linkgroup") .data(links) .enter().append("g") .attr("class", "linkgroup"); var linkpath = linkgroup.append('path') .attr("class", "linkpath") .style("fill", "none"); var planes = linkgroup.append("path") .attr("class", "plane") .attr("visibility", "hidden") .attr("d", "m25.21488,3.93375c-0.44355,0 -0.84275,0.18332 -1.17933,0.51592c-0.33397,0.33267 -0.61055,0.80884 -0.84275,1.40377c-0.45922,1.18911 -0.74362,2.85964 -0.89755,4.86085c-0.15655,1.99729 -0.18263,4.32223 -0.11741,6.81118c-5.51835,2.26427 -16.7116,6.93857 -17.60916,7.98223c-1.19759,1.38937 -0.81143,2.98095 -0.32874,4.03902l18.39971,-3.74549c0.38616,4.88048 0.94192,9.7138 1.42461,13.50099c-1.80032,0.52703 -5.1609,1.56679 -5.85232,2.21255c-0.95496,0.88711 -0.95496,3.75718 -0.95496,3.75718l7.53,-0.61316c0.17743,1.23545 0.28701,1.95767 0.28701,1.95767l0.01304,0.06557l0.06002,0l0.13829,0l0.0574,0l0.01043,-0.06557c0,0 0.11218,-0.72222 0.28961,-1.95767l7.53164,0.61316c0,0 0,-2.87006 -0.95496,-3.75718c-0.69044,-0.64577 -4.05363,-1.68813 -5.85133,-2.21516c0.48009,-3.77545 1.03061,-8.58921 1.42198,-13.45404l18.18207,3.70115c0.48009,-1.05806 0.86881,-2.64965 -0.32617,-4.03902c-0.88969,-1.03062 -11.81147,-5.60054 -17.39409,-7.89352c0.06524,-2.52287 0.04175,-4.88024 -0.1148,-6.89989l0,-0.00476c-0.15655,-1.99844 -0.44094,-3.6683 -0.90277,-4.8561c-0.22699,-0.59493 -0.50356,-1.07111 -0.83754,-1.40377c-0.33658,-0.3326 -0.73578,-0.51592 -1.18194,-0.51592l0,0l-0.00001,0l0,0z"); var planesSize = planes.node().getBBox().width; var markergroup = svg.selectAll(".markergroup") .data(cords) .enter().append("g") .attr("class", "markergroup") .attr("cursor", "pointer") .on("mousedown", function(d) { console.log(d); }); var markercircle = markergroup.append("circle") .attr("class", "markercircle") .on("mousedown", function(d) { console.log(d); }); function getcordsbyid(id) { for (var i in cords) { if (cords[i].id == id) { return cords[i].LatLng; } } } map.on("viewreset", update); update(); fly(1, 2, true); function transition(plane, route, nonstop) { var l = route.node().getTotalLength(); plane.attr("visibility", "visible"); plane.transition() .duration(l * 30) .attrTween("transform", delta(plane, route.node())) .each("end", function() { if (nonstop) { transition(plane, route, nonstop); } else { plane.attr("visibility", "hidden"); } }); } function delta(plane, path) { return function(i) { return function(t) { var l = path.getTotalLength(); var p = path.getPointAtLength(t * l); var t2 = Math.min(t + 0.05, 1); var p2 = path.getPointAtLength(t2 * l); var x = p2.x - px; var y = p2.y - py; var r = 90 - Math.atan2(-y, x) * 180 / Math.PI; var s = Math.min(Math.sin(Math.PI * t) * 0.7, 0.5); return "translate(" + (px + (planesSize / 2 * s)) + "," + (py + (planesSize / 2 * s)) + ") scale(" + s + ") rotate(" + r + ")"; } } } function fly(sourceid, targetid, nonstop) { linkgroup.filter(function(l) { if (l.source == sourceid && l.target == targetid) { return l; } }).each(function(l) { var route = d3.select(this).select(".linkpath"); var plane = d3.select(this).select(".plane"); transition(plane, route, nonstop); }); } function update() { markergroup.attr("transform", function(d) { var cor = map.latLngToLayerPoint(d.LatLng); return "translate(" + cor.x + "," + cor.y + ")"; }); linkgroup.each(function(d, i) { var route = d3.select(this).select(".linkpath").attr("d", function(l) { var slatlong = map.latLngToLayerPoint(getcordsbyid(l.source)); var tlatlong = map.latLngToLayerPoint(getcordsbyid(l.target)); var dx = tlatlong.x - slatlong.x, dy = tlatlong.y - slatlong.y, dr = Math.sqrt(dx * dx + dy * dy) * 3; return "M" + slatlong.x + "," + slatlong.y + "A" + dr + "," + dr + " 0 0,1 " + tlatlong.x + "," + tlatlong.y; }); }); } 
 html, body, #map { width: 100%; height: 100%; } .linkpath { stroke: #FF2EB9; stroke-dasharray: 10, 10; stroke-width: 2 } .markercircle { stroke: black; fill: green; r: 5; cursor: pointer; } .plane { stroke: black; stroke-width: 3; fill: white; } 
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id='map'></div> 

PS : Append the plane's path after the route's path. PS :在路径的路径追加飞机的路径。 Otherwise, the plane will fly under the route, not over it. 否则,飞机将在该路线下飞行,而不是飞越它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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