2017-03-09 26 views
3

我正试图实现this的效果。最接近我能找到的效果的一个工作示例是笛卡尔畸变效应,这似乎不适用于D3 V4。我真的不明白,所有线路需要改变或如何改变,以使这个例子与d3js版本4修改D3js V4的笛卡尔变换

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

该插件的名称为*鱼眼*。据我所知,鱼眼不适用于D3 v4。纽约时报网页和小提琴都使用鱼眼。 NYT页面使用D3 v3.3,小提琴使用D3 v2。 –

+0

是的,我知道。我想知道如果我有一个CSS解决方案来获得相同的效果 – devN

回答

0

对于什么是值得兼容我只是调整了D3-鱼眼插件与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>)