修改D3js V4的笛卡尔DIstortion

时间:2017-03-09 11:44:05

标签: d3.js

我正在努力实现this效果。最接近我能找到这种效果的工作实例是笛卡尔失真效应,它似乎与D3 V4无关。我不太了解需要更改哪些行或如何更改以使此示例与d3js版本4兼容。

jsfiddle

    (function chart3() {
  console.clear()
  var width = 960,
      height = 180,
      xSteps = d3.range(10, width, 16),
      ySteps = d3.range(10, height, 16);



  var xFisheye = d3.fisheye.scale(d3.scale.identity).domain([0, width]).focus(360),
      yFisheye = d3.scale.linear().domain([0, height]);

  var svg = d3.select("#chart3").append("svg")
      .attr("width", width)
      .attr("height", height)
    .append("g")
      .attr("transform", "translate(-.5,-.5)");

  svg.append("rect")
      .attr("class", "background")
      .attr("width", width)
      .attr("height", height);

  var xLine = svg.selectAll(".x")
      .data(xSteps)
    .enter().append("line")
      .attr("class", "x")
      .attr("y2", height);

  redraw();

  svg.on("mousemove", function() {
    var mouse = d3.mouse(this);

    // HACK ( only for left-side )
    xFisheye.focus(mouse[0] - 32);    // HACK 1
    yFisheye(mouse[1]);
    if(mouse[0] > 26)  // HACK 2
        redraw();
  });

  function redraw() {
    xLine.attr("x1", xFisheye).attr("x2", xFisheye);
  }
})();

1 个答案:

答案 0 :(得分:0)

为了它的价值,我只需调整d3-fisheye插件即可使用d3 v4。我还添加了可能有用的fisheye.invert

import * as d3 from 'd3'

const fisheye = {
  scale: function (scaleType) {
    return d3FisheyeScale(scaleType(), 3, 0)
  },
  circular: function () {
    let radius = 200
    let distortion = 2
    let k0
    let k1
    let focus = [0, 0]

    function fisheye (d) {
      let dx = d.x - focus[0]
      let dy = d.y - focus[1]
      let dd = Math.sqrt(dx * dx + dy * dy)
      if (!dd || dd >= radius) return {x: d.x, y: d.y, z: dd >= radius ? 1 : 10}
      let k = k0 * (1 - Math.exp(-dd * k1)) / dd * 0.75 + 0.25
      return {x: focus[0] + dx * k, y: focus[1] + dy * k, z: Math.min(k, 10)}
    }

    function rescale () {
      k0 = Math.exp(distortion)
      k0 = k0 / (k0 - 1) * radius
      k1 = distortion / radius
      return fisheye
    }

    fisheye.radius = function (_) {
      if (!arguments.length) return radius
      radius = +_
      return rescale()
    }

    fisheye.distortion = function (_) {
      if (!arguments.length) return distortion
      distortion = +_
      return rescale()
    }

    fisheye.focus = function (_) {
      if (!arguments.length) return focus
      focus = _
      return fisheye
    }

    return rescale()
  }
}

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

  fisheye.invert = function (xf) {
    let left = xf < a
    let range = d3.extent(scale.range())
    let min = range[0]
    let max = range[1]
    let m = left ? a - min : max - a
    if (m === 0) m = max - min
    return scale.invert(a + m * (xf - a) / ((d + 1) * m - (left ? -1 : 1) * d * (xf - a)))
  }

  fisheye.distortion = function (_) {
    if (!arguments.length) return d
    d = +_
    return fisheye
  }

  fisheye.focus = function (_) {
    if (!arguments.length) return a
    a = +_
    return fisheye
  }

  fisheye.copy = function () {
    return d3FisheyeScale(scale.copy(), d, a)
  }

  fisheye.nice = scale.nice
  fisheye.ticks = scale.ticks
  fisheye.tickFormat = scale.tickFormat

  const rebind = function (target, source) {
    let i = 1
    const n = arguments.length
    let method
    while (++i < n) {
      method = arguments[i]
      target[method] = d3Rebind(target, source, source[method])
    };
    return target
  }
  function d3Rebind (target, source, method) {
    return function () {
      var value = method.apply(source, arguments)
      return value === source ? target : value
    }
  }
  return rebind(fisheye, scale, 'domain', 'range')
}

export default fisheye

现在使用它:

import fisheye from './fisheye'
import { scaleLinear, scalePow } from 'd3-scale'

const fisheyeLinearScale = fisheye.scale(scaleLinear)
const fisheyePowScale = fisheye.scale(scalePow().exponent(1.1).copy)

const myFisheyeScale = fisheyePowScale.domain(<domain>)
                                      .range(<range>)
                                      .focus(<mouseX>)
                                      .distortion(<deformation>)