function panBehavior(selection, trackingStartCallback, trackingCallback, kineticTargetCallback, kineticEndCallback) { function mouseDown(d) { var event = d3.event; var elem = d3.select(this); d.drag.startingX = event.touches ? event.touches[0].pageX : event.layerX; if(rafId) {window.cancelAnimationFrame(rafId);rafId = null;} if (d.drag.move === false && d.drag.smoothedSpeed) { // i.e. not true or undefined or null elem.classed('stoppedChart', true); elem.classed('scrollingChart', false); this.style.webkitTransform = 'translate(' + d.drag.permX + 'px,0px)'; } else { elem.classed('stoppedChart', true); elem.classed('scrollingChart', false); d.drag.permX = d.drag.permX || 0; } d.drag.smoothedSpeed = 0; d.drag.move = true; trackingStartCallback( d.drag.permX); } function mouseMove(d) { var event = d3.event; event.preventDefault(); if (!Object.keys(d.drag).length) { return; } d.drag.lastTimestamp = event.timeStamp; var x = event.touches ? event.touches[0].pageX : event.layerX; var translateX, momentarySpeed; if (d.drag.move) { translateX = d.drag.permX + x - d.drag.startingX; this.style.webkitTransform = 'translate(' + translateX + 'px,0px)'; momentarySpeed = x - (isNaN(d.drag.prevX) ? x : d.drag.prevX); d.drag.smoothedSpeed = 0.1 * d.drag.smoothedSpeed + 0.9 * momentarySpeed; d.drag.prevX = x; trackingCallback(translateX); } } var currentPlace, flyingTarget; var elem = selection.node(); var rafId = null; function mouseUp(d) { var event = d3.event; var elem = d3.select(this); var x = event.touches ? d.drag.prevX : event.layerX; d.drag.move = false; d.drag.permX += x - d.drag.startingX; if (event.timeStamp - d.drag.lastTimestamp < 100 && Math.abs(d.drag.smoothedSpeed) > 1) { currentPlace = d.drag.permX; flyingTarget = currentPlace + (d.drag.smoothedSpeed < 0 ? Math.max(-2000, 100 * d.drag.smoothedSpeed) : Math.min(2000, 100 * d.drag.smoothedSpeed)); //d.drag.permX += flyingDistance; elem.classed('stoppedChart', false); elem.classed('scrollingChart', true); //this.style.webkitTransform = 'translate(' + d.drag.permX + 'px,0px)'; kineticTargetCallback(d.drag.permX); rafId = window.requestAnimationFrame(fly); } else { this.style.webkitTransform = 'translate(' + d.drag.permX + 'px,0px)'; trackingStartCallback(d.drag.permX); } } var prevTimestamp = null; function fly(timestamp) { if(!rafId) { prevTimestamp = null; return; } var newPlace = currentPlace + ((flyingTarget - currentPlace) < 0 ? -1 : 1) * (timestamp - ((prevTimestamp || (timestamp - (1000 / 60))))) * 0.01 * Math.abs(flyingTarget - currentPlace) / (1000 / 60); elem.style.webkitTransform = 'translate(' + newPlace + 'px,0px)'; if(Math.abs(newPlace - currentPlace) > 0.1) { currentPlace = newPlace; elem.__data__.drag.permX = newPlace; kineticTargetCallback(currentPlace); prevTimestamp = timestamp; window.requestAnimationFrame(fly); } else { rafId = null; prevTimestamp = null; } } selection.on('touchstart', mouseDown); selection.on('mousedown', mouseDown); selection.on('mousemove', mouseMove); selection.on('touchmove', mouseMove); selection.on('touchend', mouseUp); selection.on('mouseup', mouseUp); trackingStartCallback(0); selection.on('transitionend', kineticEndCallback); return selection; }