Skip to content

Commit 224646b

Browse files
committed
improvements to mouseover and mouseout
1 parent f871d43 commit 224646b

File tree

1 file changed

+113
-39
lines changed

1 file changed

+113
-39
lines changed

hknweb/templates/studentservices/course_guide_test.html

Lines changed: 113 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ <h2 style="text-align: center;">
106106
arrowhead_size = link_stroke_width*1.75,
107107
circle_radius = {{ params.circle_radius }},
108108
title_circle_radius = circle_radius * 1.2,
109-
node_stroke_width = 0,
110-
node_stroke = "gray"
109+
node_stroke_width = 1,
110+
node_stroke = "black"
111111

112112
const svg = d3.select("svg")
113113
.attr("width", width)
@@ -173,18 +173,8 @@ <h2 style="text-align: center;">
173173
const defs = svg.insert("defs", ":first-child");
174174
const arrowhead_size = link_stroke_width*1.5;
175175
for (let i = 1; i <= {{ groups|length }}; i++) {
176-
defs.append("marker")
177-
.attr("id", `head-${i}`)
178-
.attr("viewBox", `0 -${arrowhead_size} ${arrowhead_size*2} ${arrowhead_size*2}`)
179-
.attr("markerUnits", "userSpaceOnUse")
180-
.attr("refX", circle_radius + arrowhead_size*2 - link_stroke_width)
181-
.attr("refY", 0)
182-
.attr("markerWidth", arrowhead_size*2)
183-
.attr("markerHeight", arrowhead_size*2)
184-
.attr("orient", "auto")
185-
.append("path")
186-
.attr("d", `M 0 -${arrowhead_size} L ${arrowhead_size*2} 0 L 0 ${arrowhead_size}`)
187-
.attr("fill", color(i));
176+
makeMarker(`head-${i}`, color(i)); // normal
177+
makeMarker(`head-desat-${i}`, desaturate(color(i))); // desaturated
188178
}
189179

190180
// Creates the links that appear
@@ -235,10 +225,9 @@ <h2 style="text-align: center;">
235225
node.append("title")
236226
.text(d => d.id);
237227

228+
// make everything a bit transparent
238229
node.on("mouseover", function(d) {
239230
d = d.srcElement.__data__;
240-
circles
241-
.attr("opacity", 0.2);
242231

243232
let marked = new Set(),
244233
queue = [];
@@ -249,34 +238,95 @@ <h2 style="text-align: center;">
249238
marked.add(id0);
250239
queue = [...queue, ...nodeById.get(id0).bk];
251240
}
252-
circles
253-
.filter(d2 => marked.has(d2.id))
254-
.attr("opacity", 1);
255-
circles
256-
.filter(d2 => d2.id === d.id)
257-
.attr("stroke", "black")
258-
.attr("stroke-width", 3);
259-
link.filter(l => {
260-
return !marked.has(l.source.id) || !marked.has(l.target.id);
261-
})
262-
.attr("opacity", 0.05);
263-
svg.selectAll("text")
264-
.filter(d2 => d2.group !== d.group)
265-
.attr("opacity", 0.5);
266-
svg.selectAll("text")
267-
.filter(d2 => d2.id === d.id)
268-
.attr("font-weight", "bold");
241+
242+
circles.each(function(d2) {
243+
const sel = d3.select(this);
244+
if (marked.has(d2.id)) {
245+
sel.attr("fill", color(d2.group))
246+
.raise();
247+
} else {
248+
sel.attr("fill", desaturate(color(d2.group)))
249+
.lower();
250+
}
251+
if (d2.id == d.id) {
252+
sel.attr("stroke", "black")
253+
.attr("stroke-width", Math.max(1, node_stroke_width) * 3);
254+
}
255+
});
256+
link.each(function(l) {
257+
const sel = d3.select(this);
258+
const g = nodeById.get(l.source.id).group;
259+
if (marked.has(l.source.id) && marked.has(l.target.id)) {
260+
sel.attr("stroke", color(g))
261+
.attr("marker-end", `url(#head-${g})`)
262+
.raise();
263+
} else {
264+
sel.attr("stroke", desaturate(color(g)))
265+
.attr("marker-end", `url(#head-desat-${g})`)
266+
.lower();
267+
}
268+
});
269+
labels.each(function(d2) {
270+
const sel = d3.select(this);
271+
if (marked.has(d2.id)) {
272+
sel.attr("fill", "black")
273+
.raise();
274+
} else {
275+
sel.attr("fill", "#888")
276+
.lower();
277+
}
278+
});
279+
})
280+
.on("mouseout", function() {
281+
circles.attr("fill", d => color(d.group))
282+
.attr("stroke", node_stroke)
283+
.attr("stroke-width", node_stroke_width)
284+
.raise();
285+
link.attr("stroke", d => color(nodeById.get(d.source.id).group))
286+
.attr("marker-end", d => `url(#head-${nodeById.get(d.source.id).group})`)
287+
.lower();
288+
labels.attr("fill", "black")
289+
.raise();
290+
});
291+
292+
// make everything disappear
293+
/* node.on("mouseover", function(event, d) {
294+
// Collect ancestors
295+
let marked = new Set(),
296+
queue = [d.id];
297+
while (queue.length) {
298+
const id0 = queue.shift();
299+
if (marked.has(id0)) continue;
300+
marked.add(id0);
301+
queue = [...queue, ...nodeById.get(id0).bk];
302+
}
303+
304+
// Hide all circles, then show only ancestors + this node
305+
circles.attr("display", "none");
306+
circles.filter(d2 => marked.has(d2.id))
307+
.attr("display", null); // null restores default (visible)
308+
309+
// Hide all labels, then show only ancestors + this node
310+
labels.attr("display", "none");
311+
labels.filter(d2 => marked.has(d2.id))
312+
.attr("display", null);
313+
314+
// Hide all links, then show only those between ancestors
315+
link.attr("display", "none");
316+
link.filter(l => marked.has(l.source.id) && marked.has(l.target.id))
317+
.attr("display", null);
269318
})
270319
.on("mouseout", function() {
271-
svg.selectAll("circle")
272-
.attr("opacity", 1)
320+
// Restore everything
321+
circles.attr("display", null)
273322
.attr("stroke", node_stroke)
274323
.attr("stroke-width", node_stroke_width);
275-
link.attr("opacity", 1);
276-
svg.selectAll("text")
277-
.attr("opacity", 1)
324+
325+
labels.attr("display", null)
278326
.attr("font-weight", "normal");
279-
});
327+
328+
link.attr("display", null);
329+
}); */
280330

281331
simulation.on("tick", () => {
282332
link
@@ -308,6 +358,30 @@ <h2 style="text-align: center;">
308358
}
309359
}
310360

361+
// helpers
362+
function desaturate(c, amount = 0.9) {
363+
let col = d3.color(c);
364+
if (!col) return c;
365+
let hsl = d3.hsl(col);
366+
hsl.s *= (1 - amount);
367+
return hsl.formatRgb();
368+
}
369+
370+
function makeMarker(id, fillColor) {
371+
const m = defs.append("marker")
372+
.attr("id", id)
373+
.attr("viewBox", `0 -${arrowhead_size} ${arrowhead_size*2} ${arrowhead_size*2}`)
374+
.attr("markerUnits", "userSpaceOnUse")
375+
.attr("refX", circle_radius + arrowhead_size*2 - link_stroke_width)
376+
.attr("refY", 0)
377+
.attr("markerWidth", arrowhead_size*2)
378+
.attr("markerHeight", arrowhead_size*2)
379+
.attr("orient", "auto");
380+
381+
m.append("path")
382+
.attr("d", `M 0 -${arrowhead_size} L ${arrowhead_size*2} 0 L 0 ${arrowhead_size}`)
383+
.attr("fill", fillColor);
384+
}
311385

312386
return
313387
}

0 commit comments

Comments
 (0)