6

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

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

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

4

3 回答 3

3

我给你做了一个工作的例子: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';
    });
})();​
于 2012-10-11T17:28:08.353 回答
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();

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

于 2012-10-11T17:12:58.773 回答
0

我相信这条线是使用 cubism.rule 生成的,查看视图源: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 函数。

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

于 2013-03-08T17:01:08.973 回答