Loading client/src/components/ToolRecommendation.vue +63 −58 Original line number Diff line number Diff line Loading @@ -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") Loading @@ -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); }, }, Loading Loading
client/src/components/ToolRecommendation.vue +63 −58 Original line number Diff line number Diff line Loading @@ -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") Loading @@ -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); }, }, Loading