Famo.us Scrollview + TouchSync - 让 ScrollView/TouchSync 意识到 rotateZ 变换
Famo.us Scrollview + TouchSync - Make ScrollView/TouchSync Aware of rotateZ Transforms
编辑:已解决 - 查看新代码摘录
我有一个 Famo.us 滚动视图嵌套在 ContainerSurface
中。 ContainerSurface
在多点触控旋转手势上旋转,但一旦旋转,滚动视图的滚动方向就不会保持相对于旋转表面及其子项的修改器。
鉴于当前的实现,这是不可能的,问题是 TouchSync
。
要完成这样的事情,您需要编写一个自定义的 RotatedTouchSync
,即 "aware" 的旋转。这样,当 ScrollView 从 move
事件接收到 delta 时,自定义 TouchSync 已经将其转换为 ScrollView 可以理解的坐标系。
我已经用基本示例设置了一个 codepen,您可以在其中看到 ScrollView
将如何工作,除非您创建自定义 TouchSync
来提供 [=12] =] 一个转换后的 delta(正如@Joseph Carroll 所述)。
我通过使用修改后的 _handleMove
方法创建 RotatableTouchSync
来完成此修复:
function _handleMove(data) {
var history = data.history;
var currHistory = history[history.length - 1];
var prevHistory = history[history.length - 2];
var distantHistory = history[history.length - this.options.velocitySampleLength] ?
history[history.length - this.options.velocitySampleLength] :
history[history.length - 2];
var distantTime = distantHistory.timestamp;
var currTime = currHistory.timestamp;
// Begin custom code -----------------------------------------------------------------------------
var diffX, diffY, velDiffX, velDiffY;
if (this.options.rotateAngle) {
// Convert currHistory, prevHistory, distantHistory x,y points to quadrants because our formula only works when origin is 0,0
var absCenter = [window.innerWidth/2, window.innerHeight/2];
var currPrime = _calcCoordsByAngle([currHistory.x - absCenter[0], currHistory.y - absCenter[1]], this.options.rotateAngle);
var prevPrime = _calcCoordsByAngle([prevHistory.x - absCenter[0], prevHistory.y - absCenter[1]], this.options.rotateAngle);
var distPrime = _calcCoordsByAngle([distantHistory.x - absCenter[0], distantHistory.y - absCenter[1]], this.options.rotateAngle);
// Converted coordinates back to normal points (clientX, clientY points)
var convertedCurrX = currPrime.x + absCenter[0];
var convertedCurrY = currPrime.y + absCenter[1];
var convertedPrevX = prevPrime.x + absCenter[0];
var convertedPrevY = prevPrime.y + absCenter[1];
var convertedDistX = distPrime.x + absCenter[0];
var convertedDistY = distPrime.y + absCenter[1];
// Calculate diff like normal
diffX = convertedCurrX - convertedPrevX;
diffY = convertedCurrY - convertedPrevY;
velDiffX = convertedCurrX - convertedDistX;
velDiffY = convertedCurrY - convertedDistY;
}
// If the custom option for rotate angle isn't set, calculate as normal
else {
diffX = currHistory.x - prevHistory.x;
diffY = currHistory.y - prevHistory.y;
velDiffX = currHistory.x - distantHistory.x;
velDiffY = currHistory.y - distantHistory.y;
}
修改后的_handleMove
调用自定义方法_calcCoordsByAngle
:
/**
* Used to calculate a coordinate set
* at a given rotation
* See: http://math.stackexchange.com/questions/384186/calculate-new-positon-of-rectangle-corners-based-on-angle
* @method _calcCoordsByAngle
* @param {Array} oldCoords An [x,y] set of coordinates
* @param {number} phi The angle to move by
* @return {Array} The newly converted coordinates
*/
function _calcCoordsByAngle(oldCoords, phi) {
var newCoords = {};
newCoords.x = (oldCoords[0] * Math.cos(-phi)) - (oldCoords[1] * Math.sin(-phi));
newCoords.y = (oldCoords[1] * Math.cos(-phi)) + (oldCoords[0] * Math.sin(-phi));
return newCoords;
}
从那里开始,可以使用此自定义 RotatableTouchSync
替代自定义 ScrollView
上的 TouchSync
- 只需确保将 in/set 选项传递给'rotateAngle' 在 RotatableTouchSync
任何时候 Z 轴旋转发生变化。
编辑:已解决 - 查看新代码摘录
我有一个 Famo.us 滚动视图嵌套在 ContainerSurface
中。 ContainerSurface
在多点触控旋转手势上旋转,但一旦旋转,滚动视图的滚动方向就不会保持相对于旋转表面及其子项的修改器。
鉴于当前的实现,这是不可能的,问题是 TouchSync
。
要完成这样的事情,您需要编写一个自定义的 RotatedTouchSync
,即 "aware" 的旋转。这样,当 ScrollView 从 move
事件接收到 delta 时,自定义 TouchSync 已经将其转换为 ScrollView 可以理解的坐标系。
我已经用基本示例设置了一个 codepen,您可以在其中看到 ScrollView
将如何工作,除非您创建自定义 TouchSync
来提供 [=12] =] 一个转换后的 delta(正如@Joseph Carroll 所述)。
我通过使用修改后的 _handleMove
方法创建 RotatableTouchSync
来完成此修复:
function _handleMove(data) {
var history = data.history;
var currHistory = history[history.length - 1];
var prevHistory = history[history.length - 2];
var distantHistory = history[history.length - this.options.velocitySampleLength] ?
history[history.length - this.options.velocitySampleLength] :
history[history.length - 2];
var distantTime = distantHistory.timestamp;
var currTime = currHistory.timestamp;
// Begin custom code -----------------------------------------------------------------------------
var diffX, diffY, velDiffX, velDiffY;
if (this.options.rotateAngle) {
// Convert currHistory, prevHistory, distantHistory x,y points to quadrants because our formula only works when origin is 0,0
var absCenter = [window.innerWidth/2, window.innerHeight/2];
var currPrime = _calcCoordsByAngle([currHistory.x - absCenter[0], currHistory.y - absCenter[1]], this.options.rotateAngle);
var prevPrime = _calcCoordsByAngle([prevHistory.x - absCenter[0], prevHistory.y - absCenter[1]], this.options.rotateAngle);
var distPrime = _calcCoordsByAngle([distantHistory.x - absCenter[0], distantHistory.y - absCenter[1]], this.options.rotateAngle);
// Converted coordinates back to normal points (clientX, clientY points)
var convertedCurrX = currPrime.x + absCenter[0];
var convertedCurrY = currPrime.y + absCenter[1];
var convertedPrevX = prevPrime.x + absCenter[0];
var convertedPrevY = prevPrime.y + absCenter[1];
var convertedDistX = distPrime.x + absCenter[0];
var convertedDistY = distPrime.y + absCenter[1];
// Calculate diff like normal
diffX = convertedCurrX - convertedPrevX;
diffY = convertedCurrY - convertedPrevY;
velDiffX = convertedCurrX - convertedDistX;
velDiffY = convertedCurrY - convertedDistY;
}
// If the custom option for rotate angle isn't set, calculate as normal
else {
diffX = currHistory.x - prevHistory.x;
diffY = currHistory.y - prevHistory.y;
velDiffX = currHistory.x - distantHistory.x;
velDiffY = currHistory.y - distantHistory.y;
}
修改后的_handleMove
调用自定义方法_calcCoordsByAngle
:
/**
* Used to calculate a coordinate set
* at a given rotation
* See: http://math.stackexchange.com/questions/384186/calculate-new-positon-of-rectangle-corners-based-on-angle
* @method _calcCoordsByAngle
* @param {Array} oldCoords An [x,y] set of coordinates
* @param {number} phi The angle to move by
* @return {Array} The newly converted coordinates
*/
function _calcCoordsByAngle(oldCoords, phi) {
var newCoords = {};
newCoords.x = (oldCoords[0] * Math.cos(-phi)) - (oldCoords[1] * Math.sin(-phi));
newCoords.y = (oldCoords[1] * Math.cos(-phi)) + (oldCoords[0] * Math.sin(-phi));
return newCoords;
}
从那里开始,可以使用此自定义 RotatableTouchSync
替代自定义 ScrollView
上的 TouchSync
- 只需确保将 in/set 选项传递给'rotateAngle' 在 RotatableTouchSync
任何时候 Z 轴旋转发生变化。