Skip to content

Fit hierarchy diagrams to screen size in scala3doc #10873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions scala3doc/resources/dotty_res/scripts/ux.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,22 @@ window.addEventListener("DOMContentLoaded", () => {
hljs.initHighlighting();
});

var zoom;
var transform;

function showGraph() {
if ($("svg#graph").children().length == 0) {
var dotNode = document.querySelector("#dot")
if (dotNode){
var svg = d3.select("#graph");
var radialGradient = svg.append("defs").append("radialGradient").attr("id", "Gradient");
radialGradient.append("stop").attr("stop-color", "#ffd47f").attr("offset", "20%");
radialGradient.append("stop").attr("stop-color", "white").attr("offset", "100%");

var inner = svg.append("g");

// Set up zoom support
var zoom = d3.zoom()
zoom = d3.zoom()
.on("zoom", function({transform}) {
inner.attr("transform", transform);
});
Expand All @@ -76,15 +83,60 @@ function showGraph() {
g.setNode(v, {
labelType: "html",
label: g.node(v).label,
style: g.node(v).style
style: g.node(v).style,
id: g.node(v).id
});
});
g.setNode("node0Cluster", {
style: "fill: url(#Gradient);",
id: "node0Cluster"
});
g.setParent("node0", "node0Cluster");

g.edges().forEach(function(v) {
g.setEdge(v, {
arrowhead: "vee"
});
});
render(inner, g);

// Set the 'fit to content graph' upon landing on the page
var bounds = svg.node().getBBox();
var parent = svg.node().parentElement;
var fullWidth = parent.clientWidth || parent.parentNode.clientWidth,
fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
var width = bounds.width,
height = bounds.height;
var midX = bounds.x + width / 2,
midY = bounds.y + height / 2;
if (width == 0 || height == 0) return; // nothing to fit
var scale = Math.min(fullWidth / width, fullHeight / height) * 0.99; // 0.99 to make a little padding
var translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];

transform = d3.zoomIdentity
.translate(translate[0], translate[1])
.scale(scale);

svg.call(zoom.transform, transform);

// This is nasty hack to prevent DagreD3 from stretching cluster. There is similar issue on github since October 2019, but haven't been answered yet. https://github.com/dagrejs/dagre-d3/issues/377
var node0 = d3.select("g#node0")._groups[0][0];
var node0Rect = node0.children[0];
var node0Cluster = d3.select("g#node0Cluster")._groups[0][0];
var node0ClusterRect = node0Cluster.children[0];
node0Cluster.setAttribute("transform", node0.getAttribute("transform"));
node0ClusterRect.setAttribute("width", +node0Rect.getAttribute("width") + 80);
node0ClusterRect.setAttribute("height", +node0Rect.getAttribute("height") + 80);
node0ClusterRect.setAttribute("x", node0Rect.getAttribute("x") - 40);
node0ClusterRect.setAttribute("y", node0Rect.getAttribute("y") - 40);
}
}
}

function zoomOut() {
var svg = d3.select("#graph");
svg
.transition()
.duration(2000)
.call(zoom.transform, transform);
}
25 changes: 24 additions & 1 deletion scala3doc/resources/dotty_res/styles/diagram.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#graph {
width: 100%;
height: 80%;
height: 400px;
}

.diagram-class a {
Expand All @@ -29,3 +29,26 @@
.diagram-class span[data-unresolved-link] {
color: #FFF;
}

.btn {
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
transition-duration: 0.4s;
cursor: pointer;
background-color: white;
color: black;
border: 2px solid #003048;
position: absolute;
top: 0;
left: 0;
z-index:2;
}

.btn:hover {
background-color: #003048;
color: white;
}
1 change: 1 addition & 0 deletions scala3doc/resources/dotty_res/styles/scalastyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ footer .pull-right {
.diagram-class {
width: 100%;
max-height: 400px;
position: relative;
}

/* Large Screens */
Expand Down
2 changes: 1 addition & 1 deletion scala3doc/src/dotty/renderers/DotDiagramBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object DotDiagramBuilder:

val vWithId = diagram.verteciesWithId
val vertecies = vWithId.map { (vertex, id) =>
s"""node${id} [label="${getHtmlLabel(vertex, renderer)}", style="${getStyle(vertex)}"];\n"""
s"""node${id} [id=node${id}, label="${getHtmlLabel(vertex, renderer)}", style="${getStyle(vertex)}"];\n"""
}.mkString

val edges = diagram.edges.map { (from, to) =>
Expand Down
5 changes: 3 additions & 2 deletions scala3doc/src/dotty/renderers/MemberRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ class MemberRenderer(signatureRenderer: SignatureRenderer, buildNode: ContentNod
val graphHtml = MemberExtension.getFrom(m).map(_.graph) match
case Some(graph) if graph.edges.nonEmpty =>
Seq(div( id := "inheritance-diagram", cls := "diagram-class showGraph")(
input(value := "Reset zoom", `type` := "button", cls := "btn", onclick := "zoomOut()"),
svg(id := "graph"),
script(`type` := "text/dot", id := "dot")(
raw(DotDiagramBuilder.build(graph, signatureRenderer))
Expand All @@ -334,8 +335,8 @@ class MemberRenderer(signatureRenderer: SignatureRenderer, buildNode: ContentNod
renderTabs(
singleSelection = true,
Tab("Graph", "graph", graphHtml, "showGraph"),
Tab("Super types", "supertypes", supertypes),
Tab("Known subtyes", "subtypes",subtypes),
Tab("Supertypes", "supertypes", supertypes),
Tab("Known subtypes", "subtypes", subtypes),
)

private def buildDocumentableFilter = div(cls := "documentableFilter")(
Expand Down
2 changes: 2 additions & 0 deletions scala3doc/src/dotty/renderers/html.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ object HTML:
val content = Attr("content")
val testId = Attr("data-test-id")
val alt = Attr("alt")
val value = Attr("value")
val onclick=Attr("onclick")

def raw(content: String): AppliedTag = new AppliedTag(content)
def raw(content: StringBuilder): AppliedTag = content