UNPKG

d3-inertia

Version:
166 lines (148 loc) 5.84 kB
// https://github.com/Fil/d3-inertia v0.4.0 Copyright 2021 Philippe Riviere (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-selection'), require('d3-drag'), require('d3-timer'), require('versor')) : typeof define === 'function' && define.amd ? define(['exports', 'd3-selection', 'd3-drag', 'd3-timer', 'versor'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3, global.d3, global.versor)); }(this, (function (exports, d3Selection, d3Drag, d3Timer, versor) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var versor__default = /*#__PURE__*/_interopDefaultLegacy(versor); function geoInertiaDragHelper(opt) { var projection = opt.projection, v0, // Mouse position in Cartesian coordinates at start of drag gesture. r0, // Projection rotation as Euler angles at start. q0, // Projection rotation as versor at start. v10, // Mouse position in Cartesian coordinates just before end of drag gesture. v11, // Mouse position in Cartesian coordinates at end. q10; // Projection rotation as versor at end. var inertia = inertiaHelper({ start: function() { v0 = versor__default['default'].cartesian(projection.invert(inertia.position)); r0 = projection.rotate(); q0 = versor__default['default'](r0); opt.start && opt.start(); }, move: function() { var inv = projection.rotate(r0).invert(inertia.position); if (isNaN(inv[0])) return; var v1 = versor__default['default'].cartesian(inv), q1 = versor__default['default'].multiply(q0, versor__default['default'].delta(v0, v1)), r1 = versor__default['default'].rotation(q1); opt.render(r1); opt.move && opt.move(); }, end: function() { // velocity v10 = versor__default['default'].cartesian( projection.invert( inertia.position.map(function(d, i) { return d - inertia.velocity[i] / 1000; }) ) ); q10 = versor__default['default'](projection.rotate()); v11 = versor__default['default'].cartesian(projection.invert(inertia.position)); opt.end && opt.end(); }, stop: opt.stop, finish: opt.finish, render: function(t) { var rotation = versor__default['default'].rotation( versor__default['default'].multiply(q10, versor__default['default'].delta(v10, v11, t * 1000)) ); opt.render && opt.render(rotation); }, time: opt.time }); return inertia; } function geoInertiaDrag(target, render, proj, opt) { if (!opt) opt = {}; // target can be an element, a selector, a function, or a selection // but in case of a selection we make sure to reselect it with d3-selection@2 if (target.node) target = target.node(); target = d3Selection.select(target); // complete params: (projection, render, startDrag, dragging, endDrag) var inertia = geoInertiaDragHelper({ projection: proj, render: function(rotation) { proj.rotate(rotation); render && render(); }, start: opt.start, move: opt.move, end: opt.end, stop: opt.stop, finish: opt.finish, time: opt.time, hold: opt.hold }); target.call( d3Drag.drag() .on("start", inertia.start) .on("drag", inertia.move) .on("end", inertia.end) ); return inertia; } function inertiaHelper(opt) { var A = opt.time || 5000; // reference time in ms var limit = 1.0001; var B = -Math.log(1 - 1 / limit); var inertia = { start: function(e) { var position = [e.x, e.y]; inertia.position = position; inertia.velocity = [0, 0]; inertia.timer.stop(), this.classList.remove('inertia'); this.classList.add('dragging'); opt.start && opt.start.call(this, position); }, move: function(e) { var position = [e.x, e.y]; var time = performance.now(); var deltaTime = time - inertia.time; var decay = 1 - Math.exp(-deltaTime / 1000); inertia.velocity = inertia.velocity.map(function(d, i) { var deltaPos = position[i] - inertia.position[i], deltaTime = time - inertia.time; return 1000 * (1 - decay) * deltaPos / deltaTime + d * decay; }); inertia.time = time; inertia.position = position; opt.move && opt.move.call(this, position); }, end: function() { this.classList.remove('dragging', 'inertia'); var v = inertia.velocity; if (v[0] * v[0] + v[1] * v[1] < 100) return inertia.timer.stop(), opt.stop && opt.stop(); var time = performance.now(); var deltaTime = time - inertia.time; if (opt.hold == undefined) opt.hold = 100; // default flick->drag threshold time (0 disables inertia) if (deltaTime >= opt.hold) return inertia.timer.stop(), opt.stop && opt.stop(); this.classList.add('inertia'); opt.end && opt.end(); var me = this; inertia.timer.restart(function(e) { inertia.t = limit * (1 - Math.exp(-B * e / A)); opt.render && opt.render(inertia.t); if (inertia.t > 1) { inertia.timer.stop(), me.classList.remove('inertia'); inertia.velocity = [0, 0]; inertia.t = 1; opt.finish && opt.finish(); } }); }, position: [0, 0], velocity: [0, 0], // in pixels/s timer: d3Timer.timer(function(){}), time: 0 }; inertia.timer.stop(); return inertia; } exports.geoInertiaDrag = geoInertiaDrag; exports.geoInertiaDragHelper = geoInertiaDragHelper; exports.inertiaHelper = inertiaHelper; Object.defineProperty(exports, '__esModule', { value: true }); })));