@@ -395,6 +395,12 @@ void drawChart(
395395 return path;
396396 }
397397
398+ int colorIndex (int i) {
399+ // We assign colors in reverse order so that the newest versions
400+ // get the main colors.
401+ return ranges.length - i - 1 ;
402+ }
403+
398404 double legendX = xZero;
399405 double legendY =
400406 tickLabelYCoordinate + firstTickLabel.getBBox ().height + labelPadding;
@@ -403,22 +409,22 @@ void drawChart(
403409
404410 final linePaths = < SVGPathElement > [];
405411 final areaPaths = < SVGPathElement > [];
412+ final legends = < (SVGRectElement , SVGTextElement )> [];
406413 for (int i = 0 ; i < ranges.length; i++ ) {
407- // We add the lines and areas in reverse order so that the newest versions
408- // get the main colors.
409- final rangeIndex = ranges.length - 1 - i;
410- final line = computeLinePath (lines[rangeIndex]);
414+ final line = computeLinePath (lines[i]);
411415 final path = SVGPathElement ();
412- path.setAttribute ('class' , '${strokeColorClass (i )} downloads-chart-line ' );
416+ path.setAttribute (
417+ 'class' , '${strokeColorClass (colorIndex (i ))} downloads-chart-line' );
413418 path.setAttribute ('d' , '$line ' );
414419 path.setAttribute ('clip-path' , 'url(#clipRect)' );
415420 linePaths.add (path);
416421 chart.append (path);
417422
418423 if (displayAreas) {
419- final areaPath = computeLinePath (areas[rangeIndex ]);
424+ final areaPath = computeLinePath (areas[i ]);
420425 final area = SVGPathElement ();
421- area.setAttribute ('class' , '${fillColorClass (i )} downloads-chart-area ' );
426+ area.setAttribute (
427+ 'class' , '${fillColorClass (colorIndex (i ))} downloads-chart-area' );
422428 area.setAttribute ('d' , '$areaPath ' );
423429 area.setAttribute ('clip-path' , 'url(#clipRect)' );
424430 areaPaths.add (area);
@@ -428,20 +434,26 @@ void drawChart(
428434 final legend = SVGRectElement ();
429435 chart.append (legend);
430436 legend.setAttribute ('class' ,
431- 'downloads-chart-legend ${fillColorClass (i ) } ${strokeColorClass (i )}' );
437+ 'downloads-chart-legend ${fillColorClass (colorIndex ( i )) } ${strokeColorClass (colorIndex ( i ) )}' );
432438 legend.setAttribute ('height' , '$legendHeight ' );
433439 legend.setAttribute ('width' , '$legendWidth ' );
434440
435441 final legendLabel = SVGTextElement ();
436- chart.append (legendLabel);
437442 legendLabel.setAttribute ('class' , 'downloads-chart-tick-label' );
438- legendLabel.text = ranges[ranges.length - 1 - i];
443+ legendLabel.text = ranges[i];
444+ chart.append (legendLabel);
445+ legends.add ((legend, legendLabel));
446+ }
447+
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];
439452
440453 if (legendX + marginPadding + legendWidth + legendLabel.getBBox ().width >
441454 xMax) {
442455 // There is no room for the legend and label.
443- // Make a new line and update legendXCoor and legendYCoor accordingly.
444-
456+ // Make a new line and update legendX and legendY accordingly.
445457 legendX = xZero;
446458 legendY += 2 * marginPadding + legendHeight;
447459 }
@@ -476,67 +488,72 @@ void drawChart(
476488
477489 hideCursor (1 );
478490
491+ void resetHighlights () {
492+ for (int i = 0 ; i < linePaths.length; i++ ) {
493+ final l = linePaths[i];
494+ l.removeAttribute ('class' );
495+ l.setAttribute (
496+ 'class' , '${strokeColorClass (colorIndex (i ))} downloads-chart-line' );
497+
498+ if (displayAreas) {
499+ areaPaths[i].removeAttribute ('class' );
500+ areaPaths[i].setAttribute (
501+ 'class' , '${fillColorClass (colorIndex (i ))} downloads-chart-area' );
502+ }
503+ }
504+ }
505+
479506 void setHighlights (Set <int > highlightRangeIndices) {
507+ if (highlightRangeIndices.isEmpty) {
508+ resetHighlights ();
509+ }
510+
480511 for (int i = 0 ; i < ranges.length; i++ ) {
481- final rangeIndex = ranges.length - 1 - i;
482512 linePaths[i].removeAttribute ('class' );
483513 if (displayAreas) {
484514 areaPaths[i].removeAttribute ('class' );
485515 }
486516
487- if (highlightRangeIndices.contains (rangeIndex )) {
517+ if (highlightRangeIndices.contains (i )) {
488518 linePaths[i].setAttribute (
489- 'class' , '${strokeColorClass (i )} downloads-chart-line' );
519+ 'class' , '${strokeColorClass (colorIndex ( i ) )} downloads-chart-line' );
490520 if (displayAreas) {
491521 areaPaths[i].setAttribute (
492- 'class' , '${fillColorClass (i )} downloads-chart-area' );
522+ 'class' , '${fillColorClass (colorIndex ( i ) )} downloads-chart-area' );
493523 }
494524 } else if (highlightRangeIndices.isNotEmpty) {
495- linePaths[i].setAttribute (
496- 'class' , ' ${strokeColorClass (i )} downloads-chart-line-faded' );
525+ linePaths[i].setAttribute ('class' ,
526+ '${strokeColorClass (colorIndex ( i ) )} downloads-chart-line-faded' );
497527 if (displayAreas) {
498- areaPaths[i].setAttribute (
499- 'class' , ' ${fillColorClass (i )} downloads-chart-area-faded' );
528+ areaPaths[i].setAttribute ('class' ,
529+ '${fillColorClass (colorIndex ( i ) )} downloads-chart-area-faded' );
500530 }
501531 } else {
502532 linePaths[i].setAttribute (
503- 'class' , '${strokeColorClass (i )} downloads-chart-line' );
533+ 'class' , '${strokeColorClass (colorIndex ( i ) )} downloads-chart-line' );
504534 if (displayAreas) {
505- areaPaths[i].setAttribute (
506- 'class' , ' ${fillColorClass (i )} downloads-chart-area ' );
535+ areaPaths[i].setAttribute ('class' ,
536+ '${fillColorClass (colorIndex ( i ) )} downloads-chart-area ' );
507537 }
508538 }
509539 }
510540 }
511541
512- void resetHighlights () {
513- for (int i = 0 ; i < linePaths.length; i++ ) {
514- final l = linePaths[i];
515- l.removeAttribute ('class' );
516- l.setAttribute ('class' , '${strokeColorClass (i )} downloads-chart-line' );
517-
518- if (displayAreas) {
519- areaPaths[i].removeAttribute ('class' );
520- areaPaths[i]
521- .setAttribute ('class' , '${fillColorClass (i )} downloads-chart-area' );
522- }
523- }
524- }
525-
526542 svg.onMouseMove.listen ((e) {
527543 final boundingRect = svg.getBoundingClientRect ();
528- if (e.x < boundingRect.x + xZero ||
529- e.x > boundingRect.x + xMax ||
530- e.y < boundingRect.y + yMax ||
531- e.y > boundingRect.y + yZero) {
544+ final yPosition = e.y - boundingRect.y;
545+ final xPosition = e.x - boundingRect.x;
546+
547+ if (xPosition < xZero ||
548+ xPosition > xMax ||
549+ yPosition < yMax ||
550+ yPosition > yZero) {
532551 // We are outside the actual chart area
533552 resetHighlights ();
534553 hideCursor (1 );
535554 return ;
536555 }
537556
538- final yPosition = e.y - boundingRect.y;
539- final xPosition = e.x - boundingRect.x;
540557 final pointPercentage = (xPosition - xZero) / chartWidth;
541558 final nearestIndex = ((values.length - 1 ) * pointPercentage).round ();
542559 final selectedDay =
@@ -584,19 +601,19 @@ void drawChart(
584601 '${formatAbbrMonthDay (startDay )} - ${formatAbbrMonthDay (selectedDay )}' );
585602
586603 final downloads = values[nearestIndex];
587- for (int i = 0 ; i < downloads.length; i++ ) {
588- final rangeIndex = ranges.length - 1 - i;
589- if (downloads[rangeIndex] > 0 ) {
604+ for (int i = ranges.length - 1 ; i >= 0 ; i-- ) {
605+ // We traverse in reverse order so that the downloads of the newest
606+ // version is placed highest up in the tooltip.
607+ if (downloads[i] > 0 ) {
590608 // We only show the exact download count in the tooltip if it is non-zero.
591609 final square = HTMLDivElement ()
592- ..setAttribute (
593- 'class' , ' downloads-chart-tooltip-square ${squareColorClass (i )}' );
594- final rangeText = HTMLSpanElement ()..text = '${ranges [rangeIndex ]}: ' ;
610+ ..setAttribute ('class' ,
611+ 'downloads-chart-tooltip-square ${squareColorClass (colorIndex ( i ) )}' );
612+ final rangeText = HTMLSpanElement ()..text = '${ranges [i ]}: ' ;
595613 final suffix = (displayMode == DisplayMode .percentage)
596- ? ' (${(downloads [rangeIndex ] * 100 / totals [nearestIndex ]).toStringAsPrecision (2 )}%)'
614+ ? ' (${(downloads [i ] * 100 / totals [nearestIndex ]).toStringAsPrecision (2 )}%)'
597615 : '' ;
598- final text =
599- '${formatWithThousandSeperators (downloads [rangeIndex ])}$suffix ' ;
616+ final text = '${formatWithThousandSeperators (downloads [i ])}$suffix ' ;
600617 final downloadsText = HTMLSpanElement ()
601618 ..setAttribute ('class' , 'downloads-chart-tooltip-downloads' )
602619 ..text = text;
@@ -611,7 +628,7 @@ void drawChart(
611628 ..append (tooltipRange)
612629 ..append (downloadsText);
613630
614- if (highlightRangeIndices.contains (rangeIndex )) {
631+ if (highlightRangeIndices.contains (i )) {
615632 rangeText.setAttribute ('class' , 'downloads-chart-tooltip-highlight' );
616633 downloadsText.setAttribute (
617634 'class' , 'downloads-chart-tooltip-highlight' );
0 commit comments