Skip to content

Commit 34fb668

Browse files
authored
Downloads chart: highlight range on legend hover (#8620)
1 parent 82240d3 commit 34fb668

File tree

2 files changed

+65
-27
lines changed

2 files changed

+65
-27
lines changed

pkg/web_app/lib/src/widget/downloads_chart/widget.dart

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,6 @@ void drawChart(
432432
}
433433

434434
final legend = SVGRectElement();
435-
chart.append(legend);
436435
legend.setAttribute('class',
437436
'downloads-chart-legend ${fillColorClass(colorIndex(i))} ${strokeColorClass(colorIndex(i))}');
438437
legend.setAttribute('height', '$legendHeight');
@@ -442,33 +441,11 @@ void drawChart(
442441
legendLabel.setAttribute('class', 'downloads-chart-tick-label');
443442
legendLabel.text = ranges[i];
444443
chart.append(legendLabel);
444+
chart.append(legend);
445445
legends.add((legend, legendLabel));
446446
}
447447

448-
for (var i = legends.length - 1; i >= 0; i--) {
449-
// We traverse the legends in reverse order so that the legend of the newest
450-
// version is placed first.
451-
final (legend, legendLabel) = legends[i];
452-
453-
if (legendX + marginPadding + legendWidth + legendLabel.getBBox().width >
454-
xMax) {
455-
// There is no room for the legend and label.
456-
// Make a new line and update legendX and legendY accordingly.
457-
legendX = xZero;
458-
legendY += 2 * marginPadding + legendHeight;
459-
}
460-
461-
legend.setAttribute('x', '$legendX');
462-
legend.setAttribute('y', '$legendY');
463-
legendLabel.setAttribute('y', '${legendY + legendHeight}');
464-
legendLabel.setAttribute('x', '${legendX + marginPadding + legendWidth}');
465-
466-
// Update x coordinate for next legend
467-
legendX += legendWidth +
468-
marginPadding +
469-
legendLabel.getBBox().width +
470-
labelPadding;
471-
}
448+
// Setup cursor
472449

473450
final cursor = SVGLineElement()
474451
..setAttribute('class', 'downloads-chart-cursor')
@@ -479,8 +456,6 @@ void drawChart(
479456
..setAttribute('y2', '$yMax');
480457
chart.append(cursor);
481458

482-
// Setup mouse handling
483-
484459
void hideCursor(_) {
485460
cursor.setAttribute('style', 'opacity:0');
486461
toolTip.setAttribute('style', 'opacity:0;position:absolute;');
@@ -500,6 +475,8 @@ void drawChart(
500475
areaPaths[i].setAttribute(
501476
'class', '${fillColorClass(colorIndex(i))} downloads-chart-area');
502477
}
478+
legends[i].$2.removeAttribute('class');
479+
legends[i].$2.setAttribute('class', 'downloads-chart-tick-label');
503480
}
504481
}
505482

@@ -513,6 +490,7 @@ void drawChart(
513490
if (displayAreas) {
514491
areaPaths[i].removeAttribute('class');
515492
}
493+
legends[i].$2.removeAttribute('class');
516494

517495
if (highlightRangeIndices.contains(i)) {
518496
linePaths[i].setAttribute(
@@ -521,24 +499,78 @@ void drawChart(
521499
areaPaths[i].setAttribute(
522500
'class', '${fillColorClass(colorIndex(i))} downloads-chart-area');
523501
}
502+
legends[i]
503+
.$2
504+
.setAttribute('class', 'downloads-chart-legend-label-highlight');
524505
} else if (highlightRangeIndices.isNotEmpty) {
525506
linePaths[i].setAttribute('class',
526507
'${strokeColorClass(colorIndex(i))} downloads-chart-line-faded');
527508
if (displayAreas) {
528509
areaPaths[i].setAttribute('class',
529510
'${fillColorClass(colorIndex(i))} downloads-chart-area-faded');
530511
}
512+
513+
legends[i].$2.setAttribute('class', 'downloads-chart-tick-label');
531514
} else {
532515
linePaths[i].setAttribute(
533516
'class', '${strokeColorClass(colorIndex(i))} downloads-chart-line');
534517
if (displayAreas) {
535518
areaPaths[i].setAttribute('class',
536519
'${fillColorClass(colorIndex(i))} downloads-chart-area ');
537520
}
521+
legends[i].$2.setAttribute('class', 'downloads-chart-tick-label');
538522
}
539523
}
540524
}
541525

526+
// Place legends and set highlight on hover
527+
528+
for (var i = legends.length - 1; i >= 0; i--) {
529+
// We traverse the legends in reverse order so that the legend of the newest
530+
// version is placed first.
531+
final (legend, legendLabel) = legends[i];
532+
533+
if (legendX + marginPadding + legendWidth + legendLabel.getBBox().width >
534+
xMax) {
535+
// There is no room for the legend and label.
536+
// Make a new line and update legendX and legendY accordingly.
537+
legendX = xZero;
538+
legendY += 2 * marginPadding + legendHeight;
539+
}
540+
541+
legend.setAttribute('x', '$legendX');
542+
legend.setAttribute('y', '$legendY');
543+
544+
legendLabel.setAttribute('y', '${legendY + legendHeight}');
545+
legendLabel.setAttribute('x', '${legendX + marginPadding + legendWidth}');
546+
547+
// Update x coordinate for next legend
548+
legendX += legendWidth +
549+
marginPadding +
550+
legendLabel.getBBox().width +
551+
labelPadding;
552+
553+
legend.onMouseMove.listen((e) {
554+
setHighlights({i});
555+
e.stopImmediatePropagation();
556+
});
557+
legendLabel.onMouseMove.listen((e) {
558+
setHighlights({i});
559+
e.stopImmediatePropagation();
560+
});
561+
562+
legend.onMouseLeave.listen((e) {
563+
resetHighlights();
564+
e.stopImmediatePropagation();
565+
});
566+
legendLabel.onMouseLeave.listen((e) {
567+
resetHighlights();
568+
e.stopImmediatePropagation();
569+
});
570+
}
571+
572+
// Setup mouse handling on chart: show cursor, tooltip and highlights
573+
542574
svg.onMouseMove.listen((e) {
543575
final boundingRect = svg.getBoundingClientRect();
544576
final yPosition = e.y - boundingRect.y;

pkg/web_css/lib/src/_pkg.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,12 @@
395395
stroke-width: 1;
396396
}
397397

398+
.downloads-chart-legend-label-highlight {
399+
fill:var(--pub-neutral-textColor);
400+
font-size: small;
401+
font-weight: bold;
402+
}
403+
398404
.downloads-chart-fill-blue {
399405
fill:var(--pub-downloads-chart-color-0);
400406
}

0 commit comments

Comments
 (0)