Skip to content

Commit 5048810

Browse files
committed
Activity: Added hover effect in dependency graph
1 parent ae61e86 commit 5048810

File tree

2 files changed

+66
-25
lines changed

2 files changed

+66
-25
lines changed

src/app/component/dependency-graph/dependency-graph.component.css

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,26 @@ circle {
77
fill: none;
88
stroke: #000;
99
stroke-width: 1.5px;
10-
}
10+
}
11+
12+
.clickable {
13+
cursor: pointer;
14+
}
15+
16+
:host ::ng-deep svg.dependency-graph g .node-rect {
17+
fill: var(--node-fill);
18+
stroke: var(--node-border);
19+
stroke-width: 1.5;
20+
}
21+
22+
:host ::ng-deep svg.dependency-graph g.clickable {
23+
cursor: pointer;
24+
}
25+
26+
:host ::ng-deep svg.dependency-graph g.hovered .node-rect {
27+
fill: var(--node-hover-fill);
28+
}
29+
30+
:host ::ng-deep svg.dependency-graph g.main text {
31+
fill: var(--text-primary, inherit);
32+
}

src/app/component/dependency-graph/dependency-graph.component.ts

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,18 @@ export class DependencyGraphComponent implements OnInit, OnChanges {
224224
this.activityClicked.emit(d.id);
225225
}
226226
})
227-
.on('mouseover', (event: MouseEvent, d: any) => {
228-
if (this.activityClicked.observed) {
229-
if (d.relativeLevel != 0) {
230-
d3.select(event.currentTarget as Element).style('cursor', 'pointer');
231-
} else {
232-
d3.select(event.currentTarget as Element).style('cursor', 'default');
233-
}
234-
}
227+
.classed('clickable', (d: any) => this.activityClicked.observed && d.relativeLevel != 0)
228+
.classed('predecessor', (d: any) => d.relativeLevel < 0)
229+
.classed('successor', (d: any) => d.relativeLevel > 0)
230+
.classed('main', (d: any) => d.relativeLevel == 0)
231+
.style('cursor', (d: any) =>
232+
this.activityClicked.observed && d.relativeLevel != 0 ? 'pointer' : 'default'
233+
)
234+
.on('mouseover', function (_event: any, _d: any) {
235+
d3.select(this).classed('hovered', true);
235236
})
236-
.on('mouseout', (event: MouseEvent, d: any) => {
237-
d3.select(event.currentTarget as Element).style('cursor', 'default');
237+
.on('mouseout', function (_event: any, _d: any) {
238+
d3.select(this).classed('hovered', false);
238239
});
239240

240241
const rectHeight = 30;
@@ -255,29 +256,47 @@ export class DependencyGraphComponent implements OnInit, OnChanges {
255256
const self = this;
256257
nodes.each(function (this: SVGGElement, d: any) {
257258
const textElem = d3.select(this).select('text').node() as SVGTextElement;
258-
let textWidth = 60; // fallback default
259-
if (textElem && textElem.getBBox) {
260-
textWidth = textElem.getBBox().width;
259+
let textWidth = 60;
260+
if (textElem) {
261+
try {
262+
textWidth = (textElem.getBBox && textElem.getBBox().width) || textWidth;
263+
} catch {
264+
textWidth =
265+
(textElem.getComputedTextLength && textElem.getComputedTextLength()) || textWidth;
266+
}
261267
}
262-
const rectWidth = textWidth + padding;
263-
d.rectWidth = rectWidth; // Store for collision force
264-
// Insert rect before text
268+
269+
const rectWidth = Math.ceil(textWidth + padding);
270+
d.rectWidth = rectWidth; // store for collision force
271+
272+
// compute fill + hover color once
273+
const fillColor =
274+
d.relativeLevel == 0
275+
? self.themeColors.mainNodeFill || 'green'
276+
: (d.relativeLevel < 0
277+
? self.themeColors.predecessorFill
278+
: self.themeColors.successorFill) || 'white';
279+
const c = d3.color(fillColor);
280+
const hoverColor = c ? c.darker(0.6).toString() : fillColor;
281+
282+
// set CSS variables on the group so global stylesheet can use them
283+
d3.select(this)
284+
.style('--node-fill', fillColor)
285+
.style('--node-hover-fill', hoverColor)
286+
.style('--node-border', self.themeColors.borderColor || 'black');
287+
288+
// Insert rect before text sized to measured text
265289
d3.select(this)
266290
.insert('rect', 'text')
291+
.attr('class', 'node-rect')
267292
.attr('x', -rectWidth / 2)
268293
.attr('y', -rectHeight / 2)
269294
.attr('width', rectWidth)
270295
.attr('height', rectHeight)
271296
.attr('rx', rectRx)
272297
.attr('ry', rectRy)
273-
.attr('fill', (d: any) => {
274-
if (d.relativeLevel == 0) return self.themeColors.mainNodeFill || 'green';
275-
let col: string | undefined =
276-
d.relativeLevel < 0 ? self.themeColors.predecessorFill : self.themeColors.successorFill;
277-
return col || 'white';
278-
})
279-
.attr('stroke', self.themeColors.borderColor || 'black')
280-
.attr('stroke-width', 1.5);
298+
.attr('stroke-width', 1.5)
299+
.attr('stroke', 'currentColor'); // stroke taken from --node-border via CSS
281300
});
282301

283302
this.simulation.nodes(this.graphData['nodes']).on('tick', () => {

0 commit comments

Comments
 (0)