Added LowPassFilter and support for smooth scatter rotation and zoom.

This commit is contained in:
2019-07-11 15:41:03 +02:00
parent 2a11f02bd2
commit cd76ae22a4
6 changed files with 1602 additions and 1276 deletions
+1352 -1248
View File
File diff suppressed because it is too large Load Diff
+114 -15
View File
@@ -3265,8 +3265,8 @@
// Distance == 0.0 indicates an inside relation.
static distanceToRect(p, r) {
var cx = Math.max(Math.min(p.x, r.x + r.width), r.x);
var cy = Math.max(Math.min(p.y, r.y + r.height), r.y);
let cx = Math.max(Math.min(p.x, r.x + r.width), r.x);
let cy = Math.max(Math.min(p.y, r.y + r.height), r.y);
return Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
}
@@ -3702,6 +3702,92 @@
}
}
class LowPassFilter {
constructor(smoothing = 0.5, bufferMaxSize=10) {
this.smoothing = smoothing; // must be smaller than 1
this.buffer = []; // FIFO queue
this.bufferMaxSize = bufferMaxSize;
}
/**
* Setup buffer with array of values
*
* @param {array} values
* @returns {array}
* @access public
*/
setup(values) {
for (let i = 0; i < values.length; i++) {
this.__push(values[i]);
}
return this.buffer
}
/**
* Clear buffer to prepare for new values.
*
* @access public
*/
clear() {
this.buffer = [];
}
/**
* Add new value to buffer (FIFO queue)
*
* @param {integer|float} value
* @returns {integer|float}
* @access private
*/
__push(value) {
let removed = (this.buffer.length === this.bufferMaxSize)
? this.buffer.shift()
: 0;
this.buffer.push(value);
return removed
}
/**
* Smooth value from stream
*
* @param {integer|float} nextValue
* @returns {integer|float}
* @access public
*/
next(nextValue) {
// push new value to the end, and remove oldest one
let removed = this.__push(nextValue);
// smooth value using all values from buffer
let result = this.buffer.reduce((last, current) => {
return this.smoothing * current + (1 - this.smoothing) * last
}, removed);
// replace smoothed value
this.buffer[this.buffer.length - 1] = result;
return result
}
/**
* Smooth array of values
*
* @param {array} values
* @returns {undefined}
* @access public
*/
smoothArray(values) {
let value = values[0];
for (let i = 1; i < values.length; i++) {
let currentValue = values[i];
value += (currentValue - value) * this.smoothing;
values[i] = Math.round(value);
}
return values
}
}
/* global apollo, subscriptions, gql */
/**
@@ -6053,11 +6139,8 @@
window.Capabilities = Capabilities;
window.CapabilitiesTests = CapabilitiesTests;
/** Basic class for poppable elements that need to be closed as soon as one poppable is
* shown.
*/
/* eslint-disable no-unused-vars */
/**
* A base class for scatter specific events.
*
@@ -6322,7 +6405,8 @@
scaleAutoClose = false,
scaleCloseThreshold = 0.10,
scaleCloseBuffer = 0.05,
maxRotation = Angle.degree2radian(5)
maxRotation = Angle.degree2radian(5),
useLowPassFilter = true
} = {}) {
if (rotationDegrees != null && rotation != null) {
throw new Error('Use rotationDegrees or rotation but not both')
@@ -6366,7 +6450,12 @@
this.resizable = resizable;
this.mouseZoomFactor = mouseZoomFactor;
this.autoBringToFront = autoBringToFront;
this.useLowPassFilter = useLowPassFilter;
if (useLowPassFilter) {
this.rotateLPF = new LowPassFilter();
this.zoomLPF = new LowPassFilter();
this.zoomLPF.setup([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
}
this.dragging = false;
this.onTransform = onTransform != null ? [onTransform] : null;
this.onClose = onClose != null ? [onClose] : null;
@@ -6390,6 +6479,11 @@
this.bringToFront();
this.killAnimation();
this.observeVelocity();
if (this.useLowPassFilter) {
this.rotateLPF.clear();
this.zoomLPF.clear();
this.zoomLPF.setup([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
}
return true
}
@@ -6403,14 +6497,19 @@
let delta = interaction.delta();
if (delta != null) {
this.addVelocity(delta);
let alpha = delta.rotate;
let rotate = delta.rotate;
let zoom = delta.zoom;
if (this.maxRotation != null) {
if (Math.abs(alpha) > this.maxRotation) {
alpha = 0;
if (Math.abs(rotate) > this.maxRotation) {
rotate = 0;
}
}
this.transform(delta, delta.zoom, alpha, delta.about);
if (delta.zoom != 1) this.interactionAnchor = delta.about;
if (this.useLowPassFilter) {
rotate = this.rotateLPF.next(rotate);
zoom = this.zoomLPF.next(zoom);
}
this.transform(delta, zoom, rotate, delta.about);
if (zoom != 1) this.interactionAnchor = delta.about;
}
}
@@ -14870,7 +14969,7 @@
* @extends Popup
* @see {@link https://www.iwm-tuebingen.de/iwmbrowser/lib/pixi/popupmenu.html|DocTest}
*/
class PopupMenu$1 extends Popup {
class PopupMenu extends Popup {
/**
* Creates an instance of a PopupMenu.
@@ -15519,7 +15618,7 @@
window.Stylus = Stylus;
window.Switch = Switch;
window.Popup = Popup;
window.PopupMenu = PopupMenu$1;
window.PopupMenu = PopupMenu;
window.Modal = Modal;
window.Volatile = Volatile;
window.Message = Message;