当前位置: 首页 > 工具软件 > Popmotion > 使用案例 >

Popmotion动画(二) Pointer tracking 指针跟踪

艾弘义
2023-12-01

Pointer tracking指针跟踪

指针跟踪是用户界面的一个重要组成部分
Drag & drop, scrolling galleries, measuring touch scroll speed是一些显而易见的实例

在本篇中,将看到如何监听action转换成DOM事件流
然后,我们将看看如何用指针动作跟踪鼠标和触摸动作,然后使用该指针的移动来拖动DOM元素

listen

popmotion提供llisten action来监听DOM事件

import { listen } from 'popmotion';

它将接受事件名称作为空格分隔的字符串,这意味着您可以使用单个listen侦听多个事件

listen(document, 'mousedown touchstart')
  .start((e) => console.log(e));

由于listen是一个action,同样的也同样拥有一些链式方法

例如,下面是如何制作一个只有在有两个以上的触摸时才会触发的TouchMove监听器

listen(document, 'touchmove')
  .filter(({ touches }) => touches.length >= 2)
  .start((e) => /* This event has more than 2 touches! */);

Pointer

Pointer操作提供了一个通用接口,用于与单点鼠标和触摸输入交互(对于多点触摸,multitouch提供多点操作)

import { pointer } from 'popmotion';

默认情况下,指针将指针的clientX和clientY属性输出为x和y

let pointerTracker;

listen(document, 'mousedown touchstart').start(() => {
  pointerTracker = pointer()
    .start(({ x, y }) => console.log(x, y));
});

listen(document, 'mouseup touchend').start(() => {
  if (pointerTracker) pointerTracker.stop();
})

Dragging(拖拽)

在大多数情况下,我们实际上希望使用这些移动数据来拖动或滚动

让我们再次使用styler函数来创建DOM元素接口,以便提供位置数据
关注startTracking方法,并尝试写一个demo并拖动球<指#a .ball元素>

const ball = document.querySelector('#a .ball');
const ballStyler = styler(ball);
let pointerTracker;

const startTracking = () => {
  pointerTracker = pointer()
    .start(ballStyler.set);
};

const stopTracking = () => {
  if (pointerTracker) pointerTracker.stop();
};

listen(ball, 'mousedown touchstart').start(startTracking);
listen(document, 'mouseup touchend').start(stopTracking);

OK,球可以进行拖动了,但是好像,球移动到了一个奇怪的地方
原因很简单,pinter输出一个{x,y}坐标是相对于视窗

球的{x,y}从0,0开始变换。所以,如果我们把指针的绝对位置直接应用到球上,它就不会移动到我们想要的位置

const ball = document.querySelector('#b .ball');
const ballStyler = styler(ball);
let pointerTracker;

const startTracking = () => {
  pointerTracker = pointer({
    x: ballStyler.get('x'), // +++++
    y: ballStyler.get('y') // ++++
  }).start(ballStyler.set);
};

const stopTracking = () => {
  if (pointerTracker) pointerTracker.stop();
};

单轴拖动 Single-axis dragging

可以直接这样:

pointer().start(({ x }) => ballStyler.set('x', x));

但是,更可重用的方法是使用指针的管道(pipe)方法组成一个新的动作。我们可以提供一个简单的选择器函数,从指针的输出中选择x并返回它

const xPointer = (initialX) => pointer({ x: initialX })
  .pipe(({ x }) => x);

现在我们可以使用xPointer方法了

xPointer(ballStyler.get('x'))
  .start(ballStyler.set('x'));

demo:

const ball = document.querySelector('#c .ball');
const ballStyler = styler(ball);
const xPointer = (initialX) => pointer({ x: initialX })
  .pipe(({ x }) => x);

let pointerTracker;

const startTracking = () => {
  pointerTracker = xPointer(ballStyler.get('x'))
    .start(ballStyler.set('x'));
};

const stopTracking = () => {
  if (pointerTracker) pointerTracker.stop();
};

listen(ball, 'mousedown touchstart').start(startTracking);
listen(document, 'mouseup touchend').start(stopTracking);

结论

  • listen可以将DOM事件转换为值的反应流。对于利用管道和其他可链接的方法,以及使用其他操作进行组合侦听都很有用

  • pointer可以绝对输出值,或者,如果我们提供初始坐标,则可以相对地应用它的增量来输出值

  • 最后,我们可以组合新的操作来生成具有新行为( action )的可重用代码,比如单轴拖动

下一篇预告

现在我们已经开始拖动工作,在下一篇教程中,我们将学习如何检查被拖动物体的速度,并将其应用于衰变、物理和弹簧动作,以创建自然感觉的相互作用

 类似资料: