简体   繁体   English

D3.js 惯性拖动

[英]D3.js dragging with inertia

I'm trying to make dragging with inertia using d3.js and have a problem that there are some visual jerks in inertia effect, that's especially noticeable if circle will be dragged and released quickly.我正在尝试使用 d3.js 进行惯性拖动,但有一个问题,即惯性效果中存在一些视觉抖动,如果圆形将被快速拖动和释放,则这一点尤其明显。

Ideally it should work as google maps: when mouse was released circle should continue to moving smoothly for a while in the same direction and then stop.理想情况下,它应该像谷歌地图一样工作:当鼠标被释放时,圆圈应该继续沿同一方向平稳移动一段时间然后停止。

Some good example can be found here http://bl.ocks.org/pjanik/raw/5872514/ , but it implements by updating of source code of d3.js (not official I guess), while I'm interesting in implementation using official releases of d3.js.一些很好的例子可以在这里找到http://bl.ocks.org/pjanik/raw/5872514/ ,但它通过更新 d3.js 的源代码来实现(我猜不是官方的),而我对实现很感兴趣使用 d3.js 的官方版本。

Any suggestions on that?对此有何建议?

 var svg = d3.select('#parent') .append('svg') .attr('width', '100%') .attr('height', '100%'); var g = svg.append('g') .attr('transform', "translate(450, 250) scale(1)"); var circle = d3.select('g') .append('circle') .attr('class', 'circle') .attr('r', 20); function zoomed() { var transform = d3.event.transform; g.attr('transform', transform); } var mouseEvents = []; var zoomFunction = d3.zoom().on('zoom', function() { zoomed(); if (d3.event.sourceEvent) { mouseEvents.push(d3.event); if (mouseEvents.length > 5) { mouseEvents.shift(); } } }) .on('end', function() { if (d3.event.sourceEvent && mouseEvents.length) { let lastEvent = mouseEvents.shift(); let x1 = lastEvent.sourceEvent.pageX; let y1 = lastEvent.sourceEvent.pageY; let t1 = lastEvent.sourceEvent.timeStamp; let x2 = d3.event.sourceEvent.pageX; let y2 = d3.event.sourceEvent.pageY; let t2 = d3.event.sourceEvent.timeStamp; let minDistance = 20; // Deltas var dX = x2 - x1, dY = y2 - y1, dMs = Math.max(t2 - t1, 1); // Speeds var speedX = Math.max(Math.min(dX / dMs, 1), -1); var speedY = Math.max(Math.min(dY / dMs, 1), -1); // Distance moved (Euclidean distance) var distance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); if (distance > minDistance) { var position = d3.event.transform; var newLeft = position.x + (speedX * distance * 0.6), newTop = position.y + (speedY * distance * 0.6); svg .transition() .duration(350) .call( zoomFunction.transform, d3.zoomIdentity.translate(newLeft, newTop).scale(1) ); } } mouseEvents = []; }); d3.zoom().translateBy(svg, 450, 250); d3.zoom().scaleBy(svg, 1); svg.call(zoomFunction).on('dblclick.zoom', null);
 #parent { width: 900px; height: 500px; } .circle { fill: blue; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script> <div id='parent'></div>

You could use d3-inertia , which is a package that handles exactly this.您可以使用d3-inertia ,这是一个可以处理此问题的软件包。 I used this example as inspiration and got the following result:我以这个例子为灵感,得到了以下结果:

 var position = [450, 250]; var width = 500, height = 300, radius = 20; var svg = d3.select('#parent') .append('svg') .attr('width', width) .attr('height', height); var g = svg.append('g'); function draw() { g.attr('transform', `translate(${position[0]}, ${position[1]})`); } draw(); var circle = d3.select('g') .append('circle') .attr('class', 'circle') .attr('r', radius); /* Function to keep the ball inside the view */ function updatePosition(newPosition, offset) { if (offset === undefined) { offset = {x: 0, y: 0}; } newPosition[0] = Math.max(radius, Math.min(newPosition[0] + offset.x, width - radius)); newPosition[1] = Math.max(radius, Math.min(newPosition[1] + offset.y, height - radius)); position = newPosition; } function getTransformParameters(transformString) { var values = transformString.substr("translate(".length) .split(",") .map(function(d) { return parseInt(d, 10); }); return { x: values[0], y: values[1] }; } var offset = { x: 0, y: 0 }; var inertia = d3.inertiaHelper({ start: function() { var transform = getTransformParameters(g.attr("transform")); offset = { x: transform.x - inertia.position[0], y: transform.y - inertia.position[1] }; }, move: function() { updatePosition(inertia.position, offset); draw(); }, render: function(t) { updatePosition([ // velocity is constant, so I use t**2 to make it look like it slows down // 0.25 is just to slow down the ball so it doesn't fly off inertia.position[0] + 0.25 * t ** 2 * inertia.velocity[0], inertia.position[1] + 0.25 * t ** 2 * inertia.velocity[1] ]); draw(); } }); svg.call( d3.drag() .on("start", inertia.start) .on("drag", inertia.move) .on("end", inertia.end) );
 #parent { width: 900px; height: 500px; } .circle { fill: blue; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script> <script src="https://unpkg.com/d3-inertia"></script> <div id='parent'></div>

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

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