Skip to content

Commit a023840

Browse files
authored
Deploy v1.5.10
Develop v1.5.10
2 parents 4903ab5 + 84dd08b commit a023840

File tree

10 files changed

+288
-117
lines changed

10 files changed

+288
-117
lines changed

assets/settings_icon_black.svg

Lines changed: 1 addition & 0 deletions
Loading

index.html

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -114,38 +114,41 @@ <h2>📈 Time evolution</h2>
114114

115115
<div id="hoverCardContainer"></div>
116116

117-
<div class="grid-charts">
118-
<div class="chart-container" id="tagFrequencyContainer">
119-
<h2>🏷️ Tag frequency</h2>
120-
<div class="options">
121-
<div class="option-item">
122-
<label for="tagFrequencyCheckbox"
123-
title="Show percentage of appearance among all Pixels instead of raw values">Show percentages</label>
124-
<input type="checkbox" id="tagFrequencyCheckbox" class="checkbox">
125-
</div>
117+
<div class="chart-container group-options">
118+
<div class="options small title"><img src="assets/settings_icon_black.svg" alt="Settings" class="icon-settings"><span>Tag options</span></div>
126119

127-
<div class="option-item">
128-
<label for="maxTagsInput1" title="Number of tags to display">Number of tags</label>
129-
<input type="number" id="maxTagsInput1" class="input-nb input-max-tag" min="1"
130-
value="10">
131-
</div>
120+
<div class="options small">
121+
<div class="option-item">
122+
<label for="tagFrequencyCheckbox"
123+
title="Show percentage of appearance among all Pixels instead of raw values">Show percentages</label>
124+
<input type="checkbox" id="tagFrequencyCheckbox" class="checkbox">
125+
</div>
126+
127+
<div class="option-item">
128+
<label for="maxTagsInput" title="Number of tags to display">Number of tags</label>
129+
<input type="number" id="maxTagsInput" class="input-nb" min="1" value="10">
130+
</div>
131+
132+
<div class="option-item">
133+
<label for="selectTagCategory" title="Choose the category you want to display">Tag category</label>
134+
<select id="selectTagCategory" class="select"></select>
132135
</div>
136+
</div>
137+
</div>
138+
139+
<div class="grid-charts">
140+
<div class="chart-container group-options" id="tagFrequencyContainer">
141+
<h2>🏷️ Tag frequency</h2>
133142
<canvas id="tagChart" class="free-canvas"></canvas>
134143
</div>
135144

136-
<div class="chart-container" id="tagScoreContainer">
145+
<div class="chart-container group-options" id="tagScoreContainer">
137146
<h2>😊 Average score per tag</h2>
138-
<div class="options">
139-
<div class="option-item">
140-
<label for="maxTagsInput2" title="Number of tags to display">Number of tags</label>
141-
<input type="number" id="maxTagsInput2" class="input-nb input-max-tag" min="1">
142-
</div>
143-
</div>
144147
<canvas id="tagScoreChart" class="free-canvas"></canvas>
145148
</div>
146149
</div>
147150

148-
<div class="grid-charts">
151+
<div class="grid-charts group-options">
149152
<div class="chart-container" id="WeekdaysContainer">
150153
<h2>🔁 Weekdays average scores</h2>
151154
<div class="options">
@@ -453,8 +456,8 @@ <h2>📅 Search Pixels by date</h2>
453456
<img src="assets/pixels_memories_logo.png" alt="Pixels Memories">
454457
</a>
455458
</div>
456-
<div class="version">Version: v1.5.7</div>
457-
<div class="version">Last update: 2025-07-09</div>
459+
<div class="version">Version: v1.5.10</div>
460+
<div class="version">Last update: 2025-07-25</div>
458461
</footer>
459462

460463
<!-- Charts.js for graphs -->

scripts/card.js

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async function load_colored_score_SVG(score) {
3232
async function create_pixel_card(pixel) {
3333
const card = document.createElement("div");
3434
card.className = "pixel-card";
35-
35+
3636
const date = new Date(pixel.date);
3737
const formattedDate = date.toLocaleDateString(undefined, {
3838
year: "numeric", month: "long", day: "numeric"
@@ -43,40 +43,60 @@ async function create_pixel_card(pixel) {
4343
card.appendChild(title);
4444

4545
if (pixel.scores?.length) {
46-
const scoreWrapper = document.createElement("div");
47-
scoreWrapper.className = "div-pixel-score-icons";
46+
const meanScore = average(pixel.scores).toFixed(2);
47+
const div_scores = document.createElement("div");
48+
div_scores.className = "div-pixel-score-icons";
4849

4950
for (const score of pixel.scores) {
5051
const svg = await load_colored_score_SVG(score);
5152
svg.classList.add("pixel-icon");
5253

5354
const title = document.createElementNS("http://www.w3.org/2000/svg", "title");
54-
title.textContent = `Score: ${score}`;
55+
title.textContent = `Score: ${score} (day: ${meanScore})`;
5556
svg.appendChild(title);
5657

57-
scoreWrapper.appendChild(svg);
58+
div_scores.appendChild(svg);
5859
}
5960

60-
card.appendChild(scoreWrapper);
61+
card.appendChild(div_scores);
6162
}
6263

6364
if (pixel.notes) {
64-
const notes = document.createElement("div");
65-
notes.className = "div-pixel-notes";
66-
notes.innerHTML += pixel.notes.replace(/\n/g, "<br>");
67-
card.appendChild(notes);
65+
const div_notes = document.createElement("div");
66+
div_notes.className = "div-pixel-notes";
67+
div_notes.innerHTML += pixel.notes.replace(/\n/g, "<br>");
68+
card.appendChild(div_notes);
6869
}
6970

7071
if (pixel.tags.length > 0) {
71-
const tags = document.createElement("div");
72-
tags.className = "div-pixel-tags";
73-
74-
const tagStrings = pixel.tags.flatMap(tag => {
75-
return tag.entries.map(entry => `<span class="tag-pill" title="${tag.type}">${entry}</span>`);
72+
const div_tags = document.createElement("div");
73+
div_tags.className = "div-pixel-tags";
74+
75+
pixel.tags.forEach(category => {
76+
const div_tag_category = document.createElement("div");
77+
div_tag_category.className = "tag-category";
78+
79+
const tag_title = document.createElement("div");
80+
tag_title.className = "tag-category-title";
81+
tag_title.textContent = category.type;
82+
83+
const tags_container = document.createElement("div");
84+
tags_container.className = "tag-category-tags";
85+
86+
category.entries.forEach(tag => {
87+
const tag_pill = document.createElement("span");
88+
tag_pill.className = "tag-pill";
89+
tag_pill.title = category.type;
90+
tag_pill.textContent = tag;
91+
tags_container.appendChild(tag_pill);
92+
})
93+
94+
div_tag_category.appendChild(tag_title);
95+
div_tag_category.appendChild(tags_container);
96+
div_tags.appendChild(div_tag_category);
7697
});
7798

78-
tags.innerHTML += tagStrings.join("");
79-
card.appendChild(tags);
99+
card.appendChild(div_tags);
80100
}
81101

82102
if (getDynamicBorders) {

scripts/graphs.js

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,7 @@ async function create_mood_chart(data, rollingAverage, displayAverage, displayYe
7878
else if (timeOption === "words") { // number of words
7979
rawScores = data.map(entry => {
8080
if (!entry || !entry.notes) { return null; }
81-
const words = entry.notes
82-
.toLowerCase()
83-
.replace(/[^a-zA-Z0-9]+/g, " ")
84-
.split(/\s+/)
85-
.filter(word => word.replace(/[^a-zA-Z]/g, "").length >= 3);
86-
return words.length;
81+
return entry.notes.split(/\s+/).length;
8782
});
8883
minValue = maximum(rawScores);
8984
maxValue = minimum(rawScores);
@@ -241,11 +236,13 @@ async function create_tag_frequency_chart(isPercentage, maxTags) {
241236
const tagCounts = tag_stats.counts;
242237
const nbPixels = tag_stats.totalPixels;
243238
const sortedTags = Object.entries(tagCounts)
239+
.filter(tag => (tagCategory === "All") || (tagCategory === tag_stats.categories[tag[0]]))
244240
.sort(([, a], [, b]) => b - a)
245241
.slice(0, maxTags);
246242

247243
if (sortedTags.length > 0) {
248244
if (tags_frequency_chart_instance) {
245+
detach_chart_hover(tags_frequency_chart_instance);
249246
tags_frequency_chart_instance.destroy();
250247
}
251248

@@ -279,12 +276,14 @@ async function create_tag_frequency_chart(isPercentage, maxTags) {
279276
async function create_tag_score_chart(maxTags) {
280277
const tagScores = tag_stats.scores;
281278
const averages = Object.entries(tagScores)
279+
.filter(tag => (tagCategory === "All") || (tagCategory === tag_stats.categories[tag[0]]))
282280
.map(([tag, { total, count }]) => ([tag, total / count]))
283281
.sort(([, a], [, b]) => b - a)
284282
.slice(0, maxTags);
285283

286284
if (averages.length > 0) {
287285
if (tags_score_chart_instance) {
286+
detach_chart_hover(tags_score_chart_instance);
288287
tags_score_chart_instance.destroy();
289288
}
290289

@@ -321,6 +320,72 @@ async function create_tag_score_chart(maxTags) {
321320
};
322321

323322

323+
function sync_tag_hover(sourceChart, targetChart) {
324+
function remove_tooltip_target() {
325+
targetChart.setActiveElements([]);
326+
targetChart.tooltip.setActiveElements([], {});
327+
targetChart.draw();
328+
}
329+
330+
function set_tooltip_target(e) {
331+
// check if sourceChart still exists
332+
if (!sourceChart?.canvas) {
333+
return;
334+
}
335+
const tooltipActive = sourceChart.tooltip.getActiveElements();
336+
const activePoints = sourceChart.getElementsAtEventForMode(e, "index", { intersect: false, axis: "y" }, false);
337+
if ((tooltipActive.length === 0) || (activePoints.length === 0)) {
338+
remove_tooltip_target();
339+
return;
340+
}
341+
342+
const index = activePoints[0].index;
343+
const label = sourceChart.data.labels[index];
344+
const targetIndex = targetChart.data.labels.indexOf(label);
345+
if (targetIndex === -1) { return; }
346+
347+
const canvasRect = targetChart.canvas.getBoundingClientRect();
348+
const sourceRect = sourceChart.canvas.getBoundingClientRect();
349+
const relativeY = e.clientY - sourceRect.top;
350+
const centerX = canvasRect.left + canvasRect.width / 2;
351+
352+
targetChart.setActiveElements([{ datasetIndex: 0, index: targetIndex }]);
353+
targetChart.tooltip.setActiveElements(
354+
[{ datasetIndex: 0, index: targetIndex }],
355+
{ x: centerX, y: canvasRect.top + relativeY }
356+
);
357+
targetChart.update();
358+
}
359+
360+
sourceChart.canvas.addEventListener("mousemove", set_tooltip_target);
361+
sourceChart.canvas.addEventListener("mouseleave", remove_tooltip_target);
362+
363+
// Add hover handlers to the source chart
364+
sourceChart._hoverHandlers = {
365+
mousemove: set_tooltip_target,
366+
mouseleave: remove_tooltip_target
367+
};
368+
}
369+
370+
371+
function detach_chart_hover(chartInstance) {
372+
const handlers = chartInstance._hoverHandlers;
373+
if (handlers) {
374+
chartInstance.canvas.removeEventListener("mousemove", handlers.mousemove);
375+
chartInstance.canvas.removeEventListener("mouseleave", handlers.mouseleave);
376+
delete chartInstance._hoverHandlers;
377+
}
378+
}
379+
380+
381+
async function sync_tag_charts_hover() {
382+
if (tags_frequency_chart_instance && tags_score_chart_instance) {
383+
sync_tag_hover(tags_frequency_chart_instance, tags_score_chart_instance);
384+
sync_tag_hover(tags_score_chart_instance, tags_frequency_chart_instance);
385+
}
386+
}
387+
388+
324389
async function create_weekday_chart(firstDayOfWeek) {
325390
let daysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
326391
daysOfWeek = daysOfWeek.slice(firstDayOfWeek).concat(daysOfWeek.slice(0, firstDayOfWeek));

0 commit comments

Comments
 (0)