Unverified Commit 1d4460a0 authored by Martin Cech's avatar Martin Cech Committed by GitHub
Browse files

Merge pull request #15852 from anuprulez/patch-4

[23.0] Fix tool recommendations shown in a d3 js tree
parents 1ef440e9 b309e2f0
Loading
Loading
Loading
Loading
+63 −58
Original line number Diff line number Diff line
@@ -86,32 +86,59 @@ export default {
            const duration = 750;
            const maxTextLength = 20;
            const svg = d3.select("#tool-recommendation").append("svg").attr("class", "tree-size").append("g");
            const gElem = svg[0][0];
            const svgElem = gElem.parentNode;
            const svgElem = svg.node().parentElement;
            const clientH = svgElem.clientHeight;
            const clientW = svgElem.clientWidth;
            const translateX = parseInt(clientW * 0.15);

            svgElem.setAttribute("viewBox", -translateX + " 0 " + 0.5 * clientW + " " + clientH);
            svgElem.setAttribute("preserveAspectRatio", "xMidYMid meet");

            const tree = d3.tree().size([clientH, clientW]);
            const diagonal = d3.svg.diagonal().projection((d) => {
                return [d.y, d.x];
            const d3Tree = d3.tree().size([clientH, clientW]);
            root = d3.hierarchy(predictedTools, (d) => {
                return d.children;
            });
            root.x0 = parseInt(clientH / 2);
            root.y0 = 0;
            const collapse = (d) => {
                if (d.children) {
                    d._children = d.children;
                    d._children.forEach(collapse);
                    d.children = null;
                }
            };
            root.children.forEach(collapse);
            const diagonal = (s, d) => {
                const path = `M ${s.y} ${s.x}
                              C ${(s.y + d.y) / 2} ${s.x},
                              ${(s.y + d.y) / 2} ${d.x},
                              ${d.y} ${d.x}`;
                return path;
            };
            const click = (e, d) => {
                if (d.children) {
                    d._children = d.children;
                    d.children = null;
                } else {
                    d.children = d._children;
                    d._children = null;
                }
                if (d.parent == null) {
                    update(d);
                }
                const tId = d.data.id;
                if (tId !== undefined && tId !== "undefined" && tId !== null && tId !== "") {
                    document.location.href = `${getAppRoot()}tool_runner?tool_id=${tId}`;
                }
            };
            const update = (source) => {
                // Compute the new tree layout.
                const nodes = tree.nodes(root).reverse();
                const links = tree.links(nodes);
                // Normalize for fixed-depth.
                const predictedTools = d3Tree(root);
                const nodes = predictedTools.descendants();
                const links = predictedTools.descendants().slice(1);
                nodes.forEach((d) => {
                    d.y = d.depth * (clientW / 10);
                });
                // Update the nodes
                const node = svg.selectAll("g.node").data(nodes, (d) => {
                    return d.id || (d.id = ++i);
                });
                // Enter any new nodes at the parent's previous position.
                const nodeEnter = node
                    .enter()
                    .append("g")
@@ -120,97 +147,75 @@ export default {
                        return "translate(" + source.y0 + "," + source.x0 + ")";
                    })
                    .on("click", click);
                nodeEnter.append("circle").attr("r", 1e-6);
                nodeEnter.append("circle").attr("class", "node").attr("r", 1e-6);
                nodeEnter
                    .append("text")
                    .attr("dy", ".35em")
                    .attr("x", (d) => {
                        return d.children || d._children ? -10 : 10;
                    })
                    .attr("dy", ".35em")
                    .attr("text-anchor", (d) => {
                        return d.children || d._children ? "end" : "start";
                    })
                    .text((d) => {
                        const tName = d.name;
                        const tName = d.data.name;
                        if (tName.length > maxTextLength) {
                            return tName.slice(0, maxTextLength) + "...";
                        }
                        return d.name;
                        return d.data.name;
                    });
                nodeEnter.append("title").text((d) => {
                    return d.children || d._children ? d.name : "Open tool - " + d.name;
                    return d.children ? d.data.name : "Open tool - " + d.data.name;
                });
                // Transition nodes to their new position.
                const nodeUpdate = node
                const nodeUpdate = nodeEnter.merge(node);
                nodeUpdate
                    .transition()
                    .duration(duration)
                    .attr("transform", (d) => {
                        return "translate(" + d.y + "," + d.x + ")";
                    });
                nodeUpdate.select("circle").attr("r", 2.5);
                // Transition exiting nodes to the parent's new position.
                node.exit()
                nodeUpdate.select("circle.node").attr("r", 2.5);
                const nodeExit = node
                    .exit()
                    .transition()
                    .duration(duration)
                    .attr("transform", (d) => {
                        return "translate(" + source.y + "," + source.x + ")";
                    })
                    .remove();
                // Update the links
                nodeExit.select("circle").attr("r", 1e-6);
                const link = svg.selectAll("path.link").data(links, (d) => {
                    return d.target.id;
                    return d.data.id;
                });
                // Enter any new links at the parent's previous position.
                link.enter()
                const linkEnter = link
                    .enter()
                    .insert("path", "g")
                    .attr("class", "link")
                    .attr("d", (d) => {
                        const o = { x: source.x0, y: source.y0 };
                        return diagonal({ source: o, target: o });
                        return diagonal(o, o);
                    });
                const linkUpdate = linkEnter.merge(link);
                linkUpdate
                    .transition()
                    .duration(duration)
                    .attr("d", (d) => {
                        return diagonal(d, d.parent);
                    });
                // Transition links to their new position.
                link.transition().duration(duration).attr("d", diagonal);
                // Transition exiting nodes to the parent's new position.
                link.exit()
                    .transition()
                    .duration(duration)
                    .attr("d", (d) => {
                        const o = { x: source.x, y: source.y };
                        return diagonal({ source: o, target: o });
                        return diagonal(o, o);
                    })
                    .remove();
                // Stash the old positions for transition.
                nodes.forEach((d) => {
                    d.x0 = d.x;
                    d.y0 = d.y;
                });
            };
            // Toggle children on click.
            const click = (d) => {
                if (d.children) {
                    d._children = d.children;
                    d.children = null;
                } else {
                    d.children = d._children;
                    d._children = null;
                }
                update(d);
                const tId = d.id;
                if (tId !== undefined && tId !== "undefined" && tId !== null && tId !== "") {
                    document.location.href = `${getAppRoot()}tool_runner?tool_id=${tId}`;
                }
            };
            const collapse = (d) => {
                if (d.children) {
                    d._children = d.children;
                    d._children.forEach(collapse);
                    d.children = null;
                }
            };
            root = predictedTools;
            root.x0 = parseInt(clientH / 2);
            root.y0 = 0;
            root.children.forEach(collapse);
            update(root);
        },
    },