如何修改d3js鱼眼失真,使其支持半径

时间:2014-02-09 23:48:23

标签: d3.js distortion fisheye

我正在尝试修改fisheye this项目,以便我可以使用radius函数来增加鱼眼大小。我的目标是在鼠标周围看到更多的细胞。当前实现不支持半径功能。如果我使用圆形而不是缩放,我可以使用半径函数。但在这种情况下,我不知道如何使用循环。

无论哪种方式,请帮助:)

谢谢!

1 个答案:

答案 0 :(得分:3)

圆形鱼眼上的半径参数为放大效果设置了边界。相反,在比例/笛卡尔鱼眼中,整个图形被修改。聚焦单元被放大,其他单元根据它们离焦点的距离被压缩。没有边界,压缩继续平滑(逐渐变得更加压缩),直到绘图的边缘。见http://bost.ocks.org/mike/fisheye/#cartesian

如果您想要的是焦点附近的单元格没有被压缩那么多(因此您仍然可以有效地比较相邻单元格),那么要更改的参数是失真参数。较低的失真将减少聚焦单元被放大的量,因此为相邻单元留出更多空间。默认的失真参数是3,您使用的是更高的值,这会增加焦点单元的放大倍数,但会牺牲所有其他值。

如果更改失真并不能让您满意,请尝试使用d3.fisheye.scale(d3.scale.sqrt)更改比例类型;这将改变确定当您远离焦点时图像放大率如何变化的功能。 (我无法使其他比例类型起作用 - 日志会产生错误,而使用功率比例则无法设置指数。)

修改

经过额外的游戏后,我对改变输入比例类型的结果不满意。我误解了它会如何影响它:它不会改变失真的比例函数,但对于原始数据,因此焦点上方的点与焦点下方的点相比变化不同。您作为鱼眼比例参数给出的比例类型应该是对数据有意义的基础比例类型,并且不同于鱼眼效果。

相反,我尝试了一些自定义代码来将指数添加到计算中。要了解它是如何工作的,您需要先分解原始函数:

鱼眼比例的原始代码是:

function fisheye(_) {
  var x = scale(_),
      left = x < a,
      range = d3.extent(scale.range()),
      min = range[0],
      max = range[1],
      m = left ? a - min : max - a;
  if (m == 0) m = max - min;
  return a + (left ? -1 : 1) * m * (d + 1) / (d + (m / Math.abs(x - a)));
}

_是输入值,scale通常是已设置域和范围的线性比例,a是输出范围中的焦点,d 1}}是失真参数。

换句话说:确定在扭曲的比例上绘制值的点:

  • 根据默认/未失真的比例计算值的范围位置;
  • 计算它与焦点的距离({distance},Math.abs(x-a));
  • 计算图表边缘与焦点之间的距离({总距离},m);
  • 返回的值从焦点偏移{total distance}乘以
    (d + 1) / (d + ({total distance} / {distance}) );
  • 根据焦点的值是低于还是高于焦点进行适当调整。

对于未失真刻度上焦点和图形边缘之间的输入点,内部分数{total distance} / {distance}将等于2。因此,外部分数将为(d+1)/(d+2)。如果d为0(无失真),则等于1/2,输出点也将位于焦点和图形边缘之间。随着失真参数d的增加,该分数也会增加:在d=1处,输出点将是从焦点到图边缘的路径的2/3;在d=2,它将是图表边缘的3/4;等等。

相反,当输入值非常接近焦点时,{distance}接近0,因此内部分数接近无穷大而外部分数接近0,因此返回的点将非常接近焦点

最后,当输入值非常接近图的边缘时,{distance}几乎是{total distance},内部和外部分数都接近1,所以返回的点也非常接近到图的边缘。

我们想要保留的最后两个身份。我们只想改变它们之间的关系 - 当输入点离焦点越来越远并越接近图形边缘时,焦点偏移如何变化。更改失真参数会同等地改变近端和远端值的失真量。如果减少失真参数,还会降低整体放大倍数,因为所有数据仍然必须放在同一空间内。

OP希望降低焦点附近细胞之间的放大率变化率。减少失真参数可以做到这一点,但只能通过降低整体放大倍数。理想的方法是改变焦点距离和失真程度之间的关系

相同功能的已更改代码是:

function fisheye(_) {
    var x = scale(_),
        left = x < a,
        range = d3.extent(scale.range()),
        min = range[0],
        max = range[1],
        m = left ? a - min : max - a,
        dp = Math.pow(d, p);
    if (m == 0) return left? min : max;
    return a + (left ? -1 : 1) *  m  * 
      Math.pow( 
        (dp + 1)
      / (dp + (m / Math.abs(x-a) ) )
      , p);
}

我改变了两件事:我将分数(d + 1)/(d + {total distance}/{distance})提升为幂,我也将原始d值替换为相同的指数(dp )。第一个变化是改变关系,第二个变化就是调整,这样无论功率参数如何,给定的失真参数都具有大致相同的整体放大效果。

如果分数接近于零,则上升到幂的分数仍将接近于零,如果分数接近1,则仍将接近于1,因此基本身份保持不变。但是,当功率参数小于1时,变化率在边缘处较浅,在中间较陡。对于大于1的功率参数,变化率在边缘处非常陡峭,在焦点附近变浅。

此处示例:http://codepen.io/AmeliaBR/pen/zHqac
水平鱼眼尺度具有平方根幂函数(p = 0.5),而垂直具有平方函数(p = 2)。两者都具有相同的未调整失真参数(d = 6)。

平方根函数的效果是即使最远的列仍然具有一些可见宽度,但焦点附近的列宽变化是显着的。 2功能的效果是远离焦点的行被压缩到几乎不可见的高度,但焦点上方和下方的行仍然具有相当大的尺寸。我认为后一版本实现了@piedpiper所希望的。

我当然还在鱼眼比例中添加了.power函数,以便设置p参数,并将p的默认值设置为1,这将产生与原始鱼眼尺度相同的结果。我使用名称power来区分exponent {{1}} {{1}}方法,如果它们基础比例(在失真之前)具有权力关系。