如何使d3可缩放森伯斯特中的最后一个节点成为超链接?

时间:2019-07-19 10:11:05

标签: html css d3.js

我正在尝试创建d3可缩放的朝阳,以便在缩放到最后一个节点时,我希望文本(以后可能是id)成为超链接。由于我是d3 js的新手,所以我无法弄清楚。

我尝试在标题标签中附加锚标签,但仅显示在inspect window中。任何帮助将不胜感激。

    var data = <?php echo json_encode($f_data); ?>;
    console.log(data);

        partition = data => {
            const root = d3.hierarchy(data)
            .sum(d => 1)
            .sort((a, b) => b.value - a.value);
            return d3.partition()
            .size([2 * Math.PI, root.height + 1])
            (root);
        }


        var color = d3.scaleOrdinal().range(d3.quantize(d3.interpolateRainbow, data.children.length + 1));
        var format = d3.format(",d");

        var width = 632;
        var height = 500;
        var radius = width / 6;

        var arc = d3.arc()
        .startAngle(d => d.x0)
        .endAngle(d => d.x1)
        .padAngle(d => Math.min((d.x1 - d.x0) / 2, 0.005))
        .padRadius(radius * 1.5)
        .innerRadius(d => d.y0 * radius)
        .outerRadius(d => Math.max(d.y0 * radius, d.y1 * radius - 1))


        const root = partition(data);

        root.each(d => d.current = d);

        // const svg = d3.select(DOM.svg(width, width))
        const svg = d3.select("#chartContainer").append("svg")
        .style("width", width)
        .style("height", width)
        .style("font", "10px sans-serif");

        const g = svg.append("g")
        .attr("transform", `translate(${width / 2},${width / 2})`);

        const path = g.append("g")
        .selectAll("path")
        .data(root.descendants().slice(1))
        .enter().append("path")
        .attr("fill", d => { while (d.depth > 1) d = d.parent; return color(d.data.name); })
        .attr("fill-opacity", d => arcVisible(d.current) ? (d.children ? 0.6 : 0.4) : 0)
        .attr("d", d => arc(d.current));

        path.filter(d => d.children)
        .style("cursor", "pointer")
        .on("click", clicked);

        path.append("a")
        .attr("xlink:href", d => (d.children ? "#" : d.data.name)) //tried adding hyperlink
        .append("title") 
        .text(d => `${d.ancestors().map(d => d.data.name).reverse().join("/")}\n${format(d.value)}`); 
        // path.append("title")
        // .text(d => `${d.ancestors().map(d => d.data.name).reverse().join("/")}\n${format(d.value)}`);

        const label = g.append("g")
        .attr("pointer-events", "all")
        .attr("text-anchor", "middle")
        .style("user-select", "none")
        .selectAll("text")
        .data(root.descendants().slice(1))
        .enter().append("text")
        .attr("dy", "0.35em")
        .attr("fill-opacity", d => +labelVisible(d.current))
        .attr("transform", d => labelTransform(d.current))
        .text(d => d.data.name);

        const parent = g.append("circle")
        .datum(root)
        .attr("r", radius)
        .attr("fill", "none")
        .attr("pointer-events", "all")
        .on("click", clicked);

        function clicked(p) {

            parent.datum(p.parent || root);

            root.each(d => d.target = {
                x0: Math.max(0, Math.min(1, (d.x0 - p.x0) / (p.x1 - p.x0))) * 2 * Math.PI,
                x1: Math.max(0, Math.min(1, (d.x1 - p.x0) / (p.x1 - p.x0))) * 2 * Math.PI,
                y0: Math.max(0, d.y0 - p.depth),
                y1: Math.max(0, d.y1 - p.depth)
            });

            const t = g.transition().duration(750);


            path.transition(t)
            .tween("data", d => {
                const i = d3.interpolate(d.current, d.target);
                return t => d.current = i(t);
            })
            .filter(function(d) {
                return +this.getAttribute("fill-opacity") || arcVisible(d.target);
            })
            .attr("fill-opacity", d => arcVisible(d.target) ? (d.children ? 0.6 : 0.4) : 0)
            .attrTween("d", d => () => arc(d.current));

            label.filter(function(d) {
                return +this.getAttribute("fill-opacity") || labelVisible(d.target);
            }).transition(t)
            .attr("fill-opacity", d => +labelVisible(d.target))
            .attrTween("transform", d => () => labelTransform(d.current));
        }

        function arcVisible(d) {
            return d.y1 <= 3 && d.y0 >= 1 && d.x1 > d.x0;
        }

        function labelVisible(d) {
            return d.y1 <= 3 && d.y0 >= 1 && (d.y1 - d.y0) * (d.x1 - d.x0) > 0.03;
        }

        function labelTransform(d) {
            const x = (d.x0 + d.x1) / 2 * 180 / Math.PI;
            const y = (d.y0 + d.y1) / 2 * radius;
            return `rotate(${x - 90}) translate(${y},0) rotate(${x < 180 ? 0 : 180})`;
        }


        d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")");

1 个答案:

答案 0 :(得分:0)

经过无数次反复试验,我终于设法找到了解决方案。我所做的不是代替在path.filter( d => d.children)中使最后一个节点不可单击,而是将其更改为path.filter( d => d.current),这使最后一个节点可单击。现在,在function clicked(p)上添加了一条条件if语句,以检查它是否为最后一个节点。这是if语句:

path.filter(d => d.current)              // changed from d.children
        .style("cursor", "pointer")
        .on("click", clicked);           //trigger onClick function

function clicked(p) {
   if (p.current ? (p.children ? 0 : 1) : 0) {  //condition to check the last node
      window.location = "your_url";
    }
   //rest of the code follows
}

感谢@Gael给我一个提示。