【问题标题】:Smooth Javascript mousemove similar to Cubism.js类似于 Cubism.js 的平滑 Javascript mousemove
【发布时间】:2012-10-02 10:06:38
【问题描述】:

我很好奇 Mike Bostock 是如何以如此流畅的方式创建一条跟随鼠标光标的垂直线。如果你看这里http://square.github.com/cubism/,你就能明白我在说什么。

看一下我刚刚在这里制作的一个简单示例:http://jsfiddle.net/zbfUq/

在我的示例中,该行实际上消失了很多次。他是否正在做某种位置插值来在未记录的两个点之间创建平滑的平移?如果是这样,有人知道该怎么做吗?

【问题讨论】:

    标签: javascript jquery d3.js cubism.js


    【解决方案1】:

    我给你做了一个有效的例子:http://jsfiddle.net/zbfUq/37/

    基本上您已经在onmousemove 事件处理程序中记录了鼠标位置,但实际上并没有直接将线移到那里。

    然后您运行一个计时器,该计时器每隔一段时间(在我的示例中为每 10 毫秒)检查一次,并将线条移近鼠标位置。

    onmouseover事件中,我将行位置设置为鼠标位置,并设置定时器运行。

    onmouseout 事件中,我清除计时器,并将行位置设置回 0(您也可以隐藏行)。

    updatepos 函数首先检查直线距离鼠标位置的距离。如果距离小于 1px,它只是将线移动到鼠标位置。如果距离超过 1px,它会以与其距离成正比的速度移动得更近(如果线离鼠标更远,它会更快地向它移动)。

    Javascript 代码

    (function() {
        var selectline = document.getElementById('selection_line');
        var container = document.getElementById('page_content');
        var mouseX = 0;
        var lineX = 0;
    
        var linetimer;
    
        var updatepos = function () {
            var speed, distance;
            distance = Math.abs(mouseX - lineX);
            if (distance < 1) {
                lineX = mouseX;
            }
            else {
                speed = Math.round( distance / 10, 0 );
                speed = speed >= 1 ? speed : 1;
                lineX = (lineX < mouseX) ? lineX + speed : lineX - speed;
            }
    
            selectline.style.left = lineX + 'px';
    
        }
    
        $(container).on("mouseover", function(e) {
            lineX = mouseX;
            selectline.style.left = lineX + 'px';
            linetimer = setInterval(updatepos, 10);
        });
    
        $(container).on('mousemove', function(e) {
            mouseX = e.pageX;
            console.log(mouseX);
        });
    
        $(container).on("mouseout", function(e) {
            clearTimeout(linetimer);
            lineX = 0;
            selectline.style.left = LineX + 'px';
        });
    })();​
    

    【讨论】:

    • 太棒了!非常感谢您提供此代码,非常易于阅读和理解您的思维过程。但是,您是否注意到这条线会丢失(并隐藏)和一些点?主要是当你移动得太快时。我注意到,如果您逐渐适应快速鼠标移动,则不会发生这种情况……知道为什么吗?
    • 是的,我实际上是故意添加的,因为我注意到您链接到的立体主义示例表现出这种行为。要摆脱,只需从 updatepos 函数中的 if 中删除 distance &gt; 100 部分(我不确定是否包含它,但我想我会为了完整性)更新示例,此处没有跳跃:jsfiddle.net/zbfUq/39
    • 这个例子对我来说仍然很跳跃,不像 cubism.js 例子那么流畅,而且线条通常不会完全在光标下结束。别人顺利吗?
    • @Bill - 我同意,我还是很紧张。
    【解决方案2】:

    我猜他正在使用 d3.js transition,参见 https://github.com/mbostock/d3/wiki/Transitions,基本上将行(和值)从当前行位置动画到鼠标光标当前所在的位置。你可以看出他并没有试图仅仅跟随鼠标诅咒,因为如果你快速移动光标,你会看到线条有点滞后,这是过渡的动画时间。

    我在http://jsfiddle.net/2N2rt/4/ 整理了一个简单的示例,说明如何在 d3.js 中完成此操作。我没怎么玩,所以我相信你可以让它更流畅,但这看起来很不错。

    var line = d3.select('#selection_line'),
        page = d3.select('#page_content'),
        x = 0;
    
    page.on('mousemove', function() { x = d3.mouse(this)[0]; });
    
    var update = function() { 
        line.transition()
            .duration(5)
            .ease('cubic-in-out')
              .style('left', x + 'px');
    };
    
    setInterval(update, 35);
    

    还请记住,svg 元素的动画效果往往比 DOM 元素更流畅。这是一个纯粹的 svg 示例 (http://jsfiddle.net/2N2rt/10/)。

    var graph = d3.select('#graph')
                  .append('svg')
                      .attr('width', '100%')
                      .attr('height', 600);
    
    var box = graph.append('rect')
                   .attr('transform', 'translate(0, 100)')              
                   .attr('width', '100%')
                   .attr('height', 200)
                   .attr('class', 'page_content');
    
    var line = graph.append('line')
                    .attr('transform', 'translate(0, 50)') 
                    .attr({'x1': 0, 'y1' : 0, 'x2': 0, 'y2': 300})
                    .attr('class', 'selection_line');
    
    var x = 0;
    
    graph.on('mousemove', function () {
       x = d3.mouse(this)[0];         
    });
    
    var draw = function () {           
          line
            .transition()
            .duration(18)
            .attrTween('transform', d3.tween('translate(' + x + ', 50)', d3.interpolateString))
            .each('end', draw);        
    };
    
    draw();
    

    同样,这只是一个简单的示例,但希望它能给您一些想法。

    【讨论】:

    • 这很好用!它不会导致线路消失。我不知道为什么这是真的,但这正是我想要的!那么您是说我应该将“#selection_line”更改为 SVG 吗?这应该很容易做到,因为当鼠标悬停在 SVG 图形上时,线条实际上会跟随鼠标。
    • 是的,该线应该是 SVG 线,然后您应用位置变换以使用与我使用的过渡类似的过渡。由于 SVG 内置了动画支持,因此它会比移动 DOM 元素但反复更改其 css 值要平滑得多。
    • 我根据您向我展示的内容创建了一个小提琴。我仍然觉得它对我来说仍然不顺利。有什么建议?这是小提琴:jsfiddle.net/AruC7/1
    • 我在jsfiddle.net/AruC7/2 更新了你的小提琴。你在mousemove 上打电话给draw,它会不断地重置动画,让它变得断断续续。我还更新了持续时间,1718 似乎给出了最好的结果(大约 30 fps)。
    • draw() 函数中添加一个检查,类似于draw() { if (stop) return; ... }
    【解决方案3】:

    我相信这条线是使用 cubism.rule 生成的,查看 view-source:http://bost.ocks.org/mike/cubism/intro/demo-stocks.html。您需要的是以下内容:

    d3.select("body").append("div") .attr("class", "rule") .call(context.rule());

    这使用 context.rule() 来实现,一个 d3/cubism 函数。

    规则仅涵盖当前屏幕只有一个问题。向上滚动屏幕后,规则(行)就会消失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-03
      • 2012-07-09
      • 1970-01-01
      相关资源
      最近更新 更多