1

标题可能具有误导性,但这是我能想到的最好的问题摘要。

无论如何,我需要弄清楚如何制作一个列表或容器,在本例中是一个包含项目列表的普通矩形,可以上下拖动以显示容器中的其他项目。在某种程度上,它类似于带有滑块的受限 div,但没有滑块。

现在,我有了一个使用 KonvaJS 的想法,以前的 KineticJS 将容器中的所有项目放在一个组中,并使组可以在某些方向上拖动等。

然而,问题是元素向上或向下的滑动不仅应该在拖动时进行,还应该在轻弹时进行。因此,如果您向上滑动手指/鼠标,列表将继续滑动,直到最后,速度会根据滑动强度而变化。如果确定轻弹强度或速度太复杂,那么任何类型的轻弹都需要将整个列表滑动到底部或顶部。

所以这应该有点像你在你的 android 或 ios 上的标准垂直幻灯片小部件。现在您对我如何进行此操作有任何想法,或者您将如何处理。欢迎任何想法。

4

2 回答 2

1

工作演示: http: //jsbin.com/gefuvu/edit ?js,output

属性已经支持通常的拖放draggable。为了将拖放限制为垂直滚动,我使用了这个简单的dragBound:

const group = new Konva.Group({
  draggable: true,
  dragBoundFunc: (pos) => {
    const minY = -group.getClientRect().height + stage.height();
    const maxY = 0;
    const y = Math.max(Math.min(pos.y, maxY), minY);

    return {y, x: 0}
  }
});

“轻弹”实现:

// setup flick
let lastY = null;
let dY = 0;
group.on('dragstart', () => {
  lastY = group.y();
  dy = 0;
});
group.on('dragmove', () => {
    dy = lastY - group.y();
    lastY = group.y();
});
group.on('dragend', () => {
    // if last move is far way it means user move pointer very fast
    // for this case we need to automatically "scroll" group
    if (dy > 5) {
        group.to({
          y: -group.getClientRect().height + stage.height()
        });
    }
    if (dy < -5) {
        group.to({
          y: 0
        });
    }
});
于 2015-12-23T11:45:26.650 回答
1

我想当您谈论“轻弹”时,您实际上是指“滚动”。
编辑:错过了问题的重点,也错过了[konvajs]标签。但这是一种无需任何库的方法,希望它可以帮助到这种方式的人。

最简单的想法是制作两个对象,一个容器和一个内容,每个对象都有一个画布。

在鼠标wheel事件发生时,更新内容位置,然后将其画布重绘到容器的位置,或者如果您需要处理拖动,请侦听mousemove事件,将dragging标志设置为 true,然后在mouseup. 在mousemove通过检查最后一个事件的时间戳和新的时间戳计算移动速度后更新位置。然后mouseup,启动一个动画来降低你的移动速度:

// our container object
var container = {
  width: window.innerWidth - 2,
  height: window.innerHeight - 2,
  top: 0,
  left: 0,
  canvas: document.getElementById('container'),
  isOver: function(x, y) {
    return (x >= this.left && x <= this.left + this.width &&
      y >= this.top && y <= this.top + this.height);
  },
};
// our content object
var content = {
  width: container.width * 2,
  height: container.height * 2,
  top: 0,
  left: 0,
  background: 'rgba(0,255,0,.5)',
  canvas: document.createElement('canvas'),
  // set an init function to draw the texts
  init: function() {
    var ctx = this.ctx;
    ctx.font = '20px sans-serif';
    ctx.textBaseline = 'top';
    ctx.fillText('Hello World', 0, 0);
    ctx.textBaseline = 'middle';
    ctx.textAlign = 'center';
    ctx.fillText('Middle world', this.width / 2, this.height / 2);
    ctx.textBaseline = 'bottom';
    ctx.textAlign = 'left';
    var textLength = ctx.measureText('Bye World').width;
    ctx.fillText('Bye World', this.canvas.width - textLength, this.canvas.height);
    ctx.fillStyle = this.background;
    ctx.fillRect(0, 0, this.width, this.height);
  },
};
// init the objects
var init = function(obj) {
    var c = obj.canvas;
    obj.ctx = c.getContext('2d');
    c.width = obj.width;
    c.height = obj.height;
    if (obj.init) {
      obj.init();
    }
  }
  // our drawing function
var draw = function() {
  container.ctx.clearRect(0, 0, container.width, container.height);
  container.ctx.drawImage(content.canvas, content.left, content.top);
};
// update the content position
container.update = function(x, y) {
  // if the content is smaller, we don't need to scroll 
  if (content.width > container.width) {
    var maxX = Math.max(container.width, content.width);
    var minX = Math.min(container.width, content.width);

    content.left -= x;
    // if we are at one end
    if (content.left < minX - maxX) {
      content.left = minX - maxX;
    } // or another
    else if (content.left > 0) {
      content.left = 0;
    }
  }
  if (content.height > container.height) {
    var maxY = Math.max(container.height, content.height);
    var minY = Math.min(container.height, content.height);

    content.top -= y;
    if (content.top < minY - maxY) {
      content.top = minY - maxY;
    } else if (content.top > 0) {
      content.top = 0;
    }
  }
};

var drag = {
  friction: .1,
  sensibility: 18,
  minSpeed: .01,
};

var mouseMove_Handler = function(e) {
  // we're not dragging anything, stop here
  if (!drag.dragged) {
    return;
  }

  var rect = this.getBoundingClientRect();
  var posX = e.clientX - rect.left;
  var posY = e.clientY - rect.top;
  // how long did it take since last event
  var deltaTime = (e.timeStamp - drag.lastDragTime) / drag.sensibility;
  // our moving speed
  var deltaX = (drag.lastDragX - posX) / deltaTime;
  var deltaY = (drag.lastDragY - posY) / deltaTime;
  // update the drag object
  drag.lastDragX = posX;
  drag.lastDragY = posY;
  drag.lastDeltaX = deltaX;
  drag.lastDeltaY = deltaY;
  drag.lastDragTime = e.timeStamp;
  // update the container obj
  drag.dragged.update(deltaX, deltaY);
  // redraw
  draw();
};

var mouseDown_Handler = function(e) {
  // if we are sliding, stop it
  if (drag.sliding) {
    cancelAnimationFrame(drag.sliding);
    drag.sliding = null;
  }

  var rect = this.getBoundingClientRect();
  var posX = e.clientX - rect.left;
  var posY = e.clientY - rect.top;
  // first check that the event occurred on top of our container object
  // we could loop through multiple ones
  if (container.isOver(posX, posY)) {
    // init our drag object
    drag.dragged = container;
    drag.lastDragX = posX;
    drag.lastDragY = posY;
    drag.lastDragTime = e.timeStamp;

  }
};

var mouseUp_Handler = function(e) {
  // store a ref of which object we were moving
  var container = drag.dragged;
  // we're not dragging anymore
  drag.dragged = false;
  var slide = function() {
    // decrease the speed
    drag.lastDeltaX /= 1 + drag.friction;
    drag.lastDeltaY /= 1 + drag.friction;
    // check that we are still out of our minimum speed
    if (drag.lastDeltaX > drag.minSpeed || drag.lastDeltaY > drag.minSpeed ||
      drag.lastDeltaX < -drag.minSpeed || drag.lastDeltaY < -drag.minSpeed) {
      // store a reference of the animation 
      drag.sliding = requestAnimationFrame(slide);
    } else {
      drag.sliding = null;
      drag.lastDeltaX = drag.lastDeltaY = 0;
    }
    container.update(drag.lastDeltaX, drag.lastDeltaY);
    draw();
  };
  slide();
};

// add the wheel listener, for a polyfill check the MDN page : 
// https://developer.mozilla.org/en-US/docs/Web/Events/wheel#Listening_to_this_event_across_browser
var mouseWheel_Handler = function(e) {
  // get the position of our canvas element
  var rect = this.getBoundingClientRect();
  var posX = e.clientX - rect.left;
  var posY = e.clientY - rect.top;
  // first check that the event occurred on top of our container object
  if (container.isOver(posX, posY)) {
    // tell the browser we handle it
    e.preventDefault();
    e.stopPropagation();
    // send the event's deltas
    container.update(e.deltaX, e.deltaY);
    // redraw
    draw();
  }
};

container.canvas.addEventListener('mousedown', mouseDown_Handler);
container.canvas.addEventListener('mousemove', mouseMove_Handler);
container.canvas.addEventListener('mouseup', mouseUp_Handler);
container.canvas.addEventListener('mouseleave', mouseUp_Handler);
container.canvas.addEventListener('wheel', mouseWheel_Handler);

// init the objects
init(container);
init(content);
// make a first draw
draw();


// Snippet only preventions \\

// avoid the outer window to scroll
window.onscroll = function(e) {
  e.preventDefault();
  e.stopPropagation()
};

// if you go in full page view
window.onresize = function() {
  container.width = window.innerWidth;
  container.height = window.innerHeight;
  content.width = container.width * 2;
  content.height = container.height * 2;

  init(container);
  init(content);

  draw();
};
body,html,canvas {
  margin: 0;
  display: block
}
canvas {
  border: 1px solid;
}
<canvas id="container"></canvas>

于 2015-12-22T13:29:06.857 回答