Skip to content

Commit 9dab5f0

Browse files
author
Andrew Or
committed
Move styling from JS to CSS + clean up code
1 parent 107c0b6 commit 9dab5f0

File tree

3 files changed

+128
-118
lines changed

3 files changed

+128
-118
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#dag-viz-graph svg path {
19+
stroke: #444444;
20+
stroke-width: 1.5px;
21+
}
22+
23+
#dag-viz-graph svg g.cluster rect {
24+
stroke-width: 4px;
25+
stroke-opacity: 0.5;
26+
}
27+
28+
#dag-viz-graph svg g.node circle,
29+
#dag-viz-graph svg g.node rect {
30+
fill: #444444;
31+
}
32+
33+
#dag-viz-graph svg g.node.cached circle,
34+
#dag-viz-graph svg g.node.cached rect {
35+
fill: #FF0000;
36+
}
37+
38+
/* Job page specific styles */
39+
40+
#dag-viz-graph svg.job marker#marker-arrow path {
41+
fill: #444444;
42+
stroke-width: 0px;
43+
}
44+
45+
#dag-viz-graph svg.job g.cluster rect {
46+
fill: #FFFFFF;
47+
stroke: #AADFFF;
48+
}
49+
50+
#dag-viz-graph svg.job g.cluster[id*="stage"] rect {
51+
stroke: #FFDDEE;
52+
stroke-width: 6px;
53+
}
54+
55+
#dag-viz-graph svg.job g#cross-stage-edges path {
56+
fill: none;
57+
}
58+
59+
#dag-viz-graph svg.job g.cluster text {
60+
fill: #AAAAAA;
61+
font-size: 11px;
62+
}
63+
64+
/* Stage page specific styles */
65+
66+
#dag-viz-graph svg.stage g.cluster rect {
67+
fill: #F0F8FF;
68+
stroke: #AADFFF;
69+
}
70+
71+
#dag-viz-graph svg.stage g.cluster[id*="stage"] rect {
72+
fill: #FFFFFF;
73+
stroke: #FFDDEE;
74+
stroke-width: 6px;
75+
}
76+
77+
#dag-viz-graph svg.stage g.node g.label text tspan {
78+
fill: #FFFFFF;
79+
}
80+
81+
#dag-viz-graph svg.stage g.cluster text {
82+
fill: #444444;
83+
font-size: 14px;
84+
font-weight: bold;
85+
}

core/src/main/resources/org/apache/spark/ui/static/spark-dag-viz.js

Lines changed: 38 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@
5252
*/
5353

5454
var VizConstants = {
55-
rddColor: "#444444",
56-
rddCachedColor: "#FF0000",
57-
rddOperationColor: "#AADFFF",
58-
stageColor: "#FFDDEE",
59-
clusterLabelColor: "#888888",
60-
edgeColor: "#444444",
61-
edgeWidth: "1.5px",
6255
svgMarginX: 20,
6356
svgMarginY: 20,
6457
stageSep: 50,
@@ -113,17 +106,21 @@ function toggleDagViz(forJob) {
113106
function renderDagViz(forJob) {
114107

115108
// If there is not a dot file to render, fail fast and report error
109+
var jobOrStage = forJob ? "job" : "stage";
116110
if (metadataContainer().empty()) {
117111
graphContainer().append("div").text(
118-
"No visualization information available for this " + (forJob ? "job" : "stage"));
112+
"No visualization information available for this " + jobOrStage);
119113
return;
120114
}
121115

122-
var svg = graphContainer().append("svg");
116+
var svg = graphContainer().append("svg").attr("class", jobOrStage);
117+
123118
if (forJob) {
124119
renderDagVizForJob(svg);
120+
postProcessDagVizForJob();
125121
} else {
126122
renderDagVizForStage(svg);
123+
postProcessDagVizForStage();
127124
}
128125

129126
// Find cached RDDs
@@ -137,9 +134,17 @@ function renderDagViz(forJob) {
137134

138135
//
139136
resizeSvg(svg);
137+
}
140138

141-
//
142-
styleDagViz(forJob);
139+
function postProcessDagVizForJob() {
140+
}
141+
142+
function postProcessDagVizForStage() {
143+
// Round corners on RDDs on the stage page
144+
graphContainer()
145+
.selectAll("svg.stage g.node rect")
146+
.attr("rx", "5")
147+
.attr("ry", "5");
143148
}
144149

145150
/*
@@ -216,6 +221,7 @@ function renderDagVizForJob(svgContainer) {
216221
var crossStageEdges = [];
217222

218223
metadataContainer().selectAll(".stage-metadata").each(function(d, i) {
224+
// Set up container
219225
var metadata = d3.select(this);
220226
var dot = metadata.select(".dot-file").text();
221227
var stageId = metadata.attr("stageId");
@@ -226,11 +232,14 @@ function renderDagVizForJob(svgContainer) {
226232
var container = svgContainer
227233
.append("a").attr("xlink:href", stageLink)
228234
.append("g").attr("id", containerId);
235+
229236
// Now we need to shift the container for this stage so it doesn't overlap
230237
// with existing ones. We do not need to do this for the first stage.
231238
if (i > 0) {
232239
// Take into account the position and width of the last stage's container
233-
var existingStages = stageClusters();
240+
var existingStages = graphContainer()
241+
.selectAll("svg g.cluster")
242+
.filter("[id*=\"" + VizConstants.stageClusterPrefix + "\"]");
234243
if (!existingStages.empty()) {
235244
var lastStage = d3.select(existingStages[0].pop());
236245
var lastStageId = lastStage.attr("id");
@@ -262,25 +271,6 @@ function renderDagVizForJob(svgContainer) {
262271
connectRDDs(fromRDDId, toRDDId, container);
263272
}
264273
}
265-
}
266-
267-
/* Render the dot file as an SVG in the given container. */
268-
function renderDot(dot, container) {
269-
var escaped_dot = dot
270-
.replace(/&lt;/g, "<")
271-
.replace(/&gt;/g, ">")
272-
.replace(/&quot;/g, "\"");
273-
var g = graphlibDot.read(escaped_dot);
274-
var renderer = new dagreD3.render();
275-
renderer(container, g);
276-
}
277-
278-
/* Style the visualization we just rendered. */
279-
function styleDagViz(forJob) {
280-
graphContainer()
281-
.selectAll("svg path")
282-
.style("stroke", VizConstants.edgeColor)
283-
.style("stroke-width", VizConstants.edgeWidth);
284274

285275
// Put an arrow at the end of every edge
286276
// We need to do this because we manually render some edges ourselves
@@ -289,77 +279,19 @@ function styleDagViz(forJob) {
289279
graphContainer().select("svg")
290280
.append(function() { return dagreD3Marker.cloneNode(true); })
291281
.attr("id", "marker-arrow")
292-
.select("path")
293-
.attr("fill", VizConstants.edgeColor)
294-
.attr("strokeWidth", "0px");
295282
graphContainer().selectAll("svg g > path").attr("marker-end", "url(#marker-arrow)");
296283
graphContainer().selectAll("svg g.edgePaths def").remove(); // We no longer need these
297-
298-
// Apply any job or stage specific styles
299-
if (forJob) {
300-
styleDagVizForJob();
301-
} else {
302-
styleDagVizForStage();
303-
}
304284
}
305285

306-
/* Apply job-page-specific style to the visualization. */
307-
function styleDagVizForJob() {
308-
graphContainer()
309-
.selectAll("svg g.cluster rect")
310-
.style("fill", "white")
311-
.style("stroke", VizConstants.rddOperationColor)
312-
.style("stroke-width", "4px")
313-
.style("stroke-opacity", "0.5");
314-
stageClusters()
315-
.select("rect")
316-
.style("stroke", VizConstants.stageColor)
317-
.style("strokeWidth", "6px");
318-
graphContainer()
319-
.selectAll("svg g.node circle")
320-
.style("fill", VizConstants.rddColor);
321-
// TODO: add a legend to explain what a highlighted dot means
322-
graphContainer()
323-
.selectAll("svg g.cached circle")
324-
.style("fill", VizConstants.rddCachedColor);
325-
graphContainer()
326-
.selectAll("svg g#cross-stage-edges path")
327-
.style("fill", "none");
328-
graphContainer()
329-
.selectAll("svg g.cluster text")
330-
.attr("fill", VizConstants.clusterLabelColor)
331-
.attr("font-size", "11px");
332-
}
333-
334-
/* Apply stage-page-specific style to the visualization. */
335-
function styleDagVizForStage() {
336-
graphContainer()
337-
.selectAll("svg g.cluster rect")
338-
.style("fill", "#F0F8FF")
339-
.style("stroke", VizConstants.rddOperationColor)
340-
.style("stroke-width", "4px")
341-
.style("stroke-opacity", "0.5");
342-
stageClusters()
343-
.select("rect")
344-
.style("fill", "white")
345-
.style("stroke", VizConstants.stageColor)
346-
.style("strokeWidth", "6px");
347-
graphContainer()
348-
.selectAll("svg g.node rect")
349-
.style("fill", "#444444")
350-
.attr("rx", "5") // round corners
351-
.attr("ry", "5");
352-
graphContainer()
353-
.selectAll("svg g.cached rect")
354-
.style("fill", VizConstants.rddCachedColor)
355-
graphContainer()
356-
.selectAll("svg g.node g.label text tspan")
357-
.style("fill", "white");
358-
graphContainer()
359-
.selectAll("svg g.cluster text")
360-
.attr("fill", "#444444")
361-
.attr("font-size", "14px")
362-
.attr("font-weight", "bold")
286+
/* Render the dot file as an SVG in the given container. */
287+
function renderDot(dot, container) {
288+
var escaped_dot = dot
289+
.replace(/&lt;/g, "<")
290+
.replace(/&gt;/g, ">")
291+
.replace(/&quot;/g, "\"");
292+
var g = graphlibDot.read(escaped_dot);
293+
var renderer = new dagreD3.render();
294+
renderer(container, g);
363295
}
364296

365297
/*
@@ -371,10 +303,8 @@ function getAbsolutePosition(d3selection) {
371303
throw "Attempted to get absolute position of an empty selection.";
372304
}
373305
var obj = d3selection;
374-
var _x = obj.attr("x") || 0,
375-
_y = obj.attr("y") || 0;
376-
_x = toFloat(_x);
377-
_y = toFloat(_y);
306+
var _x = toFloat(obj.attr("x")) || 0;
307+
var _y = toFloat(obj.attr("y")) || 0;
378308
while (!obj.empty()) {
379309
var transformText = obj.attr("transform");
380310
if (transformText) {
@@ -395,7 +325,7 @@ function getAbsolutePosition(d3selection) {
395325
/* (Job page only) Connect two RDD nodes with a curved edge. */
396326
function connectRDDs(fromRDDId, toRDDId, container) {
397327
var fromNodeId = VizConstants.nodePrefix + fromRDDId;
398-
var toNodeId = VizConstants.nodePrefix + toRDDId
328+
var toNodeId = VizConstants.nodePrefix + toRDDId;
399329
var fromPos = getAbsolutePosition(graphContainer().select("#" + fromNodeId));
400330
var toPos = getAbsolutePosition(graphContainer().select("#" + toNodeId));
401331

@@ -445,15 +375,12 @@ function connectRDDs(fromRDDId, toRDDId, container) {
445375
container.append("path").datum(points).attr("d", line);
446376
}
447377

448-
/* Helper d3 accessor to clusters that represent stages. */
449-
function stageClusters() {
450-
return graphContainer()
451-
.selectAll("svg g.cluster")
452-
.filter("[id*=\"" + VizConstants.stageClusterPrefix + "\"]");
453-
}
454-
455378
/* Helper method to convert attributes to numeric values. */
456379
function toFloat(f) {
457-
return parseFloat(f.toString().replace(/px$/, ""));
380+
if (f) {
381+
return parseFloat(f.toString().replace(/px$/, ""));
382+
} else {
383+
return f;
384+
}
458385
}
459386

core/src/main/scala/org/apache/spark/ui/UIUtils.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,10 @@ private[spark] object UIUtils extends Logging {
156156

157157
def commonHeaderNodes: Seq[Node] = {
158158
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
159-
<link rel="stylesheet" href={prependBaseUri("/static/bootstrap.min.css")}
160-
type="text/css" />
161-
<link rel="stylesheet" href={prependBaseUri("/static/webui.css")}
162-
type="text/css" />
163-
<link rel="stylesheet" href={prependBaseUri("/static/vis.min.css")}
164-
typ="text/css" />
165-
<link rel="stylesheet" href={prependBaseUri("/static/timeline-view.css")}></link>
159+
<link rel="stylesheet" href={prependBaseUri("/static/bootstrap.min.css")} type="text/css" />
160+
<link rel="stylesheet" href={prependBaseUri("/static/webui.css")} type="text/css" />
161+
<link rel="stylesheet" href={prependBaseUri("/static/vis.min.css")} type="text/css" />
162+
<link rel="stylesheet" href={prependBaseUri("/static/timeline-view.css")} type="text/css" />
166163
<script src={prependBaseUri("/static/sorttable.js")} ></script>
167164
<script src={prependBaseUri("/static/jquery-1.11.1.min.js")}></script>
168165
<script src={prependBaseUri("/static/vis.min.js")}></script>
@@ -174,6 +171,7 @@ private[spark] object UIUtils extends Logging {
174171
}
175172

176173
def vizHeaderNodes: Seq[Node] = {
174+
<link rel="stylesheet" href={prependBaseUri("/static/spark-dag-viz.css")} type="text/css" />
177175
<script src={prependBaseUri("/static/d3.min.js")}></script>
178176
<script src={prependBaseUri("/static/dagre-d3.min.js")}></script>
179177
<script src={prependBaseUri("/static/graphlib-dot.min.js")}></script>

0 commit comments

Comments
 (0)