zoukankan      html  css  js  c++  java
  • drag

    简述

    Drag-and-drop(拖拽) 是一种很流行的交互方式。 D3的 drag behavior 为[selections](https://github.com/d3/d3-selection交互, 例如你可以使用拖拽交互来增强 力导向效果,或者拖拽力学仿真中相互碰撞的圆:

    JS Bin on jsbin.com

    你也可以使用拖拽交互来做一些传统的控件,比如滑块等。但是拖拽交互并不局限于移动元素,有很多种响应拖拽操作的方式,比如可以使用它来套索散点图中的元素,或者使用canvas画图。

    拖拽交互对元素不敏感,所以你可以将其应用在SVG,HTML甚至Canvas上。并且可以通过其他技术手段对其进行扩展,比如可以将Voronoi叠加到目标元素上:

    JS Bin on jsbin.com JS Bin on jsbin.com

    有一点好处,那就是拖拽操作统一了鼠标触摸输入,并且屏蔽了浏览器的差异性。如果支持Pointer Events 那么也支持拖拽操作。

    W3C对Pointer的定义为:以任何输入设备在屏幕上做出接触点的效果,比如鼠标,笔,触摸等。

    A pointer can be any point of contact on the screen made by a mouse cursor, pen, touch (including multi-touch), or other pointing input device

    Installing

    NPM等安装方法略

    <script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
    <script src="https://d3js.org/d3-selection.v1.min.js"></script>
    <script src="https://d3js.org/d3-drag.v1.min.js"></script>
    <script>
    
    var drag = d3.drag();
    
    </script>
    

    Try d3-drag in your browser.

    API Reference

    下面的表格描述了拖拽事件与原始Pointer Event之间的对应关系:

    EventListening ElementDrag EventDefault Prevented?
    mousedown? selection start no¹
    mousemove² window¹ drag yes
    mouseup² window¹ end yes
    dragstart² window - yes
    selectstart² window - yes
    click³ window - yes
    touchstart selection start no?
    touchmove selection drag yes
    touchend selection end no?
    touchcancel selection end no?

    所有的事件传播会被阻止,如果要防止某些非拖拽事件触发拖拽事件监听器,则要设置 drag.filter来对事件进行过滤.

    # d3.drag() <>

    创建一个新的拖拽操作,返回一个drag, 它是一个对象方法。一般通过 selection.call将其应用在指定的选择集上.

    # drag(selection) <>

    将拖拽操作应用到指定的选择集。这个方法并不会直接使用,在内部通过使用 selection.call间接调用. 比如使用如下方法为选择集添加拖拽事件:

    d3.selectAll(".node").call(d3.drag().on("start", started));
    

    在内部,拖拽操作通过selection.on 来为元素添加监听事件. 事件监听器使用 .drag 来标识这是一个拖拽事件, 所以你可以通过如下方法来取消拖拽操作:

    selection.on(".drag", null);
    

    应用拖拽操作时,在IOS上也会同步改变 -webkit-tap-highlight-color 来高亮显示拖拽的元素,如果你想自定义高亮颜色,则需要在应用拖拽交互后移除或重新应用这个样式.

    # drag.container([container]) <>

    拖拽事件中,当前的鼠标坐标是常常被使用到的,那么当前的鼠标位置如何计算,是相对于哪个祖先元素?这就需要通过container来设置。

    如果指定了container,则设置拖拽事件的相对祖先元素,并返回当前的拖拽对象。如果没有设置container则返回当前的祖先元素访问器,默认:

    function container() {
      return this.parentNode;
    }
    

    container指定了拖拽事件的坐标系统,对 event.x 和 event.y有影响. 由container访问器返回的元素最后会被传给d3.moused3.touch 来计算事件的具体坐标.

    默认的容器访问器返回选择集的父级元素,这种默认设置经常被用来操作SVG和HTML,因为这些元素通常使用相对父元素的定位来获取坐标。如果拖拽Canvas上的图元元素,则需要设置容器为元素自身:

    function container() {
      return this;
    }
    

    当然也可以直接设置,而不是使用访问器的形式,比如drag.container(canvas).

    # drag.filter([filter]) <>

    如果指定了 filter,则设置事件过滤器,并返回拖拽行为,如果没有指定 filter 则返回当前的过滤器,默认为:

    function filter() {
      return !d3.event.button;
    }
    

    如果过滤器返回false,则会忽略这个事件,并没有拖拽行为发生。过滤器决定了哪些输入事件应当被忽略。默认的过滤器会忽略辅助按钮上的鼠标按下事件,因为这些按钮通常有其他的目的,比如菜单按钮.

    # drag.subject([subject]) <>

    如果subject指定了,则设置当前的 subject 访问器为指定的对象或者函数,并返回当前的拖拽操作。如果没有指定subject,则返回当前的 subject 访问器,默认为:

    function subject(d) {
      return d == null ? {x: event.x, y: event.y} : d;
    }
    

    subject 表示 当前正被拖拽的东西。当接收到输入事件时被计算得到,比如鼠标按下或者开始触摸等在拖拽开始之前。然后 subject 作为event.subject被附加到drag events上。

    默认的 subject 是接收拖拽事件的原始元素上绑定的datum;如果datum未定义,则表示指针坐标位置的对象会被创建。当在SVG中拖拽圆时,默认的subject就是当前被拖拽圆上绑定的数据。当使用Canvas时,默认的subject就是当前canvas元素上的datum(无论你点击的是canvas上的哪个位置)。当使用canvas时,自定义的subject访问器就显得非常重要了,比如在当前位置指定半径区域内选取一个圆表示当前被拖拽的对象:

    function subject() {
      var n = circles.length,
          i,
          dx,
          dy,
          d2,
          s2 = radius * radius,
          circle,
          subject;
    
      for (i = 0; i < n; ++i) {
        circle = circles[i];
        dx = d3.event.x - circle.x;
        dy = d3.event.y - circle.y;
        d2 = dx * dx + dy * dy;
        if (d2 < s2) subject = circle, s2 = d2;
      }
    
      return subject;
    }
    

    如果需要的话,上述操作可以使用quadtree.find来加速。

    返回的subject应该是一个包含x和y属性的对象,所以subject和指针在拖拽过程中的相对位置可以保持。如果subject为null或者undefined,则不会启动拖拽手势;然而,其他的起始点也可以启动 拖拽手势,参考drag.filter。

    拖拽过程中的subject可能在拖拽过程中没有变化。拖拽访问器和selection.on事件会以相同的上下文和参数被调用:当前数据d,索引i以及指向当前DOM元素的this。在对subject访问器进行计算过程中,d3.event是一个先于drag event启动的事件。使用event.sourceEvent可以访问原始事件,event.identifier可以访问原始触摸标识符。event.x 和 event.y坐标是想对于container并使用d3.mouse 或 d3.touch计算的,

    # drag.on(typenames, [listener]) <>

    如果指定了listener,则将其设置为指定类型的回调事件,并返回拖拽对象。如果已经为执行的typename注册了监听器,则会将其覆盖。如果listener为null,则相当于移除typename对应的监听器。如果没有指定listener,则返回与typename匹配的第一个监听器。当事件发生时,对应的监听器将会被执行,并传递当前元素绑定的数据 d 和索引 i, this 指向当前DOM元素.

    typenames 是一个或多个由空格分割的字符串. 每个 typename 都是一个可以由(.)分割的 typename, 比如drag.foodrag.bar; name 允许为同一种type添加多个监听器,而type必须为如下几种:

    • start - 开始拖拽 (对应 mousedown 或 touchstart).
    • drag - 拖拽中 (对应 mousemove 或 touchmove).
    • end - 拖拽结束 (对应 mouseup, touchend 或 touchcancel).

    参考 dispatch.on 获取更多信息.

    # d3.dragDisable(window) <>

    阻止指定窗口上的原生拖拽和文本选择事件。

    # d3.dragEnable(window[, noclick]) <>

    启用指定window上的原生拖拽和文本选择事件,取消d3.dragDisable的影响.

    Drag Events

    When a drag event listener is invoked, d3.event is set to the current drag event. The event object exposes several fields:

    • target - the associated drag behavior.
    • type - 事件类型, “start”, “drag” or “end”; 参考 drag.on.
    • subject - 由 drag.subject定义的.
    • x - 新的 x-坐标,鼠标当前的位置.
    • y - 新的 y-坐标,鼠标当前的位置.
    • dx - 相对与上个拖拽事件的x-方向的偏移.
    • dy - 相对与上个拖拽事件的y-方向的偏移.
    • identifier - 触发事件的设备, “mouse”, 或 touch identifier.
    • active - 当前活动的拖放操作数量.
    • sourceEvent - 底层原生事件, 比如mousemove 或 touchmove.

    event.active 在多个拖放并发进行时是有用的。记录了同时进行拖放操作的数量。

    The event object also exposes the event.on method.

    # event.on(typenames, [listener]) <>

    相当于drag.on, 但是只能应用于当前的拖拽操作。在进行拖拽之前,会创建一个event listeners 副本. 这个副本通过event.on被绑定到当前的拖拽操作。这可以用来创建一个临时的拖拽监听器,例如通过闭包创建一个临时的拖拽事件监听器:

    function started() {
      var circle = d3.select(this).classed("dragging", true);
    
      d3.event.on("drag", dragged).on("end", ended);
    
      function dragged(d) {
        circle.raise().attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
      }
    
      function ended() {
        circle.classed("dragging", false);
      }
    }
    
  • 相关阅读:
    46. Permutations 全排列,无重复
    243. Shortest Word Distance 最短的单词index之差
    171. Excel Sheet Column Number Excel列号转数字
    179. Largest Number 用数组中的元素凑一个最大数字
    49. Group Anagrams 多组anagram合并
    电话号码的字母组合(leetcode17)
    最接近的三数之和(leetcode16)
    c#之dynamic类型通过属性获取值(get value by key)
    三数之和(leetcode15)
    java-list与array转换
  • 原文地址:https://www.cnblogs.com/yaoyinglong/p/drag.html
Copyright © 2011-2022 走看看