Skip to content
This repository was archived by the owner on Jul 5, 2025. It is now read-only.

Commit 1d1f452

Browse files
authored
Fix the labels and legend visibility (#16)
1 parent 43b0fc0 commit 1d1f452

File tree

2 files changed

+65
-33
lines changed

2 files changed

+65
-33
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ org.gradle.jvmargs=-Xmx4096m
99
# Project properties
1010
config.group = xyz.marinkovic.milos
1111
config.artifact = codestats
12-
config.version = 0.10.0
12+
config.version = 0.11.0
1313
config.gitHubRepoOwner = milosmns
1414
config.gitHubRepoName = code-stats

src/commonMain/resources/web/js/script.js

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,15 @@ document.addEventListener('DOMContentLoaded', function () {
308308

309309
// CHARTING AND PAGE UPDATES
310310

311+
String.prototype.hashCode = function () {
312+
let hash = 0;
313+
for (let i = 0; i < this.length; i++) {
314+
const char = this.charCodeAt(i);
315+
hash = (hash << 5) - hash + char;
316+
}
317+
return hash;
318+
};
319+
311320
function prepareBreakdownChartData(metricTimeSeries, breakdownSourceSelector, averageSelector) {
312321
// this finds the dataset for this date, for example a breakdown by author
313322
// and then collects all the keys from that dataset (i.e. all authors)
@@ -393,15 +402,29 @@ document.addEventListener('DOMContentLoaded', function () {
393402
}
394403

395404
function getColorFromKey(key) {
396-
let hash = 0;
397-
for (let i = 0; i < key.length; i++) {
398-
hash = key.charCodeAt(i) + ((hash << 5) - hash);
399-
}
405+
// Use hash to ensure consistent random variations for the same key
406+
const randomSeed = Math.abs(key.hashCode());
407+
408+
// Define acceptable hue ranges (avoiding red)
409+
const hueRanges = [
410+
[30, 60], // Orange
411+
[240, 300], // Purple
412+
];
413+
414+
const baseHue = randomSeed % 300; // Using a larger range to account for avoided red
415+
const baseSaturation = (randomSeed * 2654435761) % 31 + 70; // Between 70% and 100%
416+
const baseLightness = (randomSeed * 2654435761) % 61 + 20; // Between 20% and 80%
417+
418+
// Calculate hue variation within acceptable ranges
419+
const hueVariation = (Math.random() * 61 - 30 + randomSeed) % 300;
400420

401-
// adjust hue to generate predominantly blue and green colors
402-
const hue = Math.floor((Math.sin(hash++) + 1) / 2 * 120 + 150);
403-
const saturation = Math.floor((Math.sin(hash++) + 1) / 2 * 50 + 30);
404-
const lightness = Math.floor((Math.sin(hash++) + 1) / 2 * 30 + 50);
421+
// Find the acceptable hue range
422+
const acceptableRange = hueRanges.find(range => baseHue + hueVariation >= range[0] && baseHue + hueVariation <= range[1]);
423+
424+
// Calculate final hue within the chosen range
425+
const hue = (baseHue + hueVariation + (acceptableRange ? acceptableRange[1] : 0) - 30) % 360;
426+
const saturation = Math.min(Math.max(baseSaturation, 0), 100);
427+
const lightness = baseLightness;
405428

406429
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
407430
}
@@ -410,33 +433,27 @@ document.addEventListener('DOMContentLoaded', function () {
410433
var gridLine;
411434
var titleColor;
412435

413-
function setUpChart(metricTimeSeries, breakdownSourceSelector, averageSelector, chartId, chartTitle, chartParentId) {
436+
function setUpChart(
437+
metricTimeSeries,
438+
breakdownSourceSelector,
439+
averageSelector,
440+
chartId,
441+
chartTitle,
442+
chartParentId,
443+
showLegend,
444+
forceLabels = false,
445+
) {
414446
var chartElement = document.getElementById(chartId);
415447
var chartParentElement = document.getElementById(chartParentId);
416448
var canvas = chartElement.getContext('2d');
417449

418450
var chartData = prepareBreakdownChartData(metricTimeSeries, breakdownSourceSelector, averageSelector);
419451
var labelToTimeSeriesList = Object.entries(chartData.yValuesMap);
420-
// usually useless after 50 labels, while hover still works. large datasets are dots so they're ok to display
421-
var showLegend = labelToTimeSeriesList.length < 200;
422-
var disableLabelsDueToSize = showLegend && (labelToTimeSeriesList.length > 7 && labelToTimeSeriesList.length < 50 || labelToTimeSeriesList.length > 200);
452+
// usually useless when there are a lot of labels; hide by default when too many
453+
var disableLabelsDueToSize = labelToTimeSeriesList.length > 15;
423454
var hasAverages = chartData.averages.some(item => item !== null);
424-
425455
var datasets = [];
426-
for (const [sourceKey, timeSeries] of labelToTimeSeriesList) {
427-
var disableLabelsDueToLackOfData = timeSeries.every(item => item === null);
428-
datasets.push({
429-
label: sourceKey,
430-
data: timeSeries,
431-
cubicInterpolationMode: 'monotone',
432-
tension: 0.4,
433-
backgroundColor: [getColorFromKey(sourceKey)],
434-
borderColor: [getColorFromKey(sourceKey)],
435-
borderWidth: 2.5,
436-
spanGaps: true,
437-
hidden: disableLabelsDueToSize || disableLabelsDueToLackOfData,
438-
});
439-
};
456+
440457
if (hasAverages) {
441458
datasets.push({
442459
label: 'Average',
@@ -452,6 +469,21 @@ document.addEventListener('DOMContentLoaded', function () {
452469
});
453470
}
454471

472+
for (const [sourceKey, timeSeries] of labelToTimeSeriesList) {
473+
var disableLabelsDueToLackOfData = timeSeries.every(item => item === null);
474+
datasets.push({
475+
label: sourceKey,
476+
data: timeSeries,
477+
cubicInterpolationMode: 'monotone',
478+
tension: 0.4,
479+
backgroundColor: [getColorFromKey(sourceKey)],
480+
borderColor: [getColorFromKey(sourceKey)],
481+
borderWidth: 2.5,
482+
spanGaps: true,
483+
hidden: !forceLabels && (disableLabelsDueToSize || disableLabelsDueToLackOfData),
484+
});
485+
};
486+
455487
var chartConfig = new Chart(canvas, {
456488
type: 'line',
457489
data: {
@@ -816,11 +848,11 @@ document.addEventListener('DOMContentLoaded', function () {
816848
var perRepositorySelector = (metricOnDate) => metricOnDate.perRepository;
817849
var repositoriesAverageSelector = (metricOnDate) => metricOnDate.averagePerRepository;
818850

819-
setUpChart(data, perAuthorSelector, authorsAverageSelector, 'chart-per-author', 'Authors breakdown', 'chart-per-author-wrapper');
820-
setUpChart(data, perReviewerSelector, reviewersAverageSelector, 'chart-per-reviewer', 'Reviewers breakdown', 'chart-per-reviewer-wrapper');
821-
setUpChart(data, perCodeReviewSelector, codeReviewsAverageSelector, 'chart-per-code-review', 'Code reviews breakdown', 'chart-per-code-review-wrapper');
822-
setUpChart(data, perDiscussionSelector, discussionsAverageSelector, 'chart-per-discussion', 'Discussions breakdown', 'chart-per-discussion-wrapper');
823-
setUpChart(data, perRepositorySelector, repositoriesAverageSelector, 'chart-per-repository', 'Repositories breakdown', 'chart-per-repository-wrapper');
851+
setUpChart(data, perAuthorSelector, authorsAverageSelector, 'chart-per-author', 'Authors breakdown', 'chart-per-author-wrapper', true);
852+
setUpChart(data, perReviewerSelector, reviewersAverageSelector, 'chart-per-reviewer', 'Reviewers breakdown', 'chart-per-reviewer-wrapper', true);
853+
setUpChart(data, perCodeReviewSelector, codeReviewsAverageSelector, 'chart-per-code-review', 'Code reviews breakdown', 'chart-per-code-review-wrapper', false, true);
854+
setUpChart(data, perDiscussionSelector, discussionsAverageSelector, 'chart-per-discussion', 'Discussions breakdown', 'chart-per-discussion-wrapper', true);
855+
setUpChart(data, perRepositorySelector, repositoriesAverageSelector, 'chart-per-repository', 'Repositories breakdown', 'chart-per-repository-wrapper', true);
824856
})
825857
.catch(function (error) {
826858
console.error('Error fetching data: ', error);

0 commit comments

Comments
 (0)