Skip to content

Commit 84dd08b

Browse files
committed
Feat(tags): sync tooltips on tag canvas
1 parent 3691345 commit 84dd08b

File tree

3 files changed

+91
-51
lines changed

3 files changed

+91
-51
lines changed

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ <h2>📅 Search Pixels by date</h2>
456456
<img src="assets/pixels_memories_logo.png" alt="Pixels Memories">
457457
</a>
458458
</div>
459-
<div class="version">Version: v1.5.9</div>
459+
<div class="version">Version: v1.5.10</div>
460460
<div class="version">Last update: 2025-07-25</div>
461461
</footer>
462462

scripts/graphs.js

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ async function create_tag_frequency_chart(isPercentage, maxTags) {
242242

243243
if (sortedTags.length > 0) {
244244
if (tags_frequency_chart_instance) {
245+
detach_chart_hover(tags_frequency_chart_instance);
245246
tags_frequency_chart_instance.destroy();
246247
}
247248

@@ -282,6 +283,7 @@ async function create_tag_score_chart(maxTags) {
282283

283284
if (averages.length > 0) {
284285
if (tags_score_chart_instance) {
286+
detach_chart_hover(tags_score_chart_instance);
285287
tags_score_chart_instance.destroy();
286288
}
287289

@@ -311,52 +313,77 @@ async function create_tag_score_chart(maxTags) {
311313
}
312314
}
313315
});
314-
315-
// if (tags_frequency_chart_instance && tags_score_chart_instance) {
316-
// sync_charts_hover(tags_frequency_chart_instance, tags_score_chart_instance);
317-
// sync_charts_hover(tags_score_chart_instance, tags_frequency_chart_instance);
318-
// }
319316
}
320317
else {
321318
tag_scores_container.style.display = "none";
322319
}
323320
};
324321

325322

326-
/*
327-
async function sync_charts_hover(sourceChart, targetChart) {
328-
async function remove_tooltip_target() {
323+
function sync_tag_hover(sourceChart, targetChart) {
324+
function remove_tooltip_target() {
329325
targetChart.setActiveElements([]);
330-
targetChart.tooltip.setActiveElements([], { x: 0, y: 0 });
326+
targetChart.tooltip.setActiveElements([], {});
331327
targetChart.draw();
332328
}
333329

334-
sourceChart.canvas.addEventListener("mousemove", (e) => {
330+
function set_tooltip_target(e) {
331+
// check if sourceChart still exists
332+
if (!sourceChart?.canvas) {
333+
return;
334+
}
335335
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();
336+
const activePoints = sourceChart.getElementsAtEventForMode(e, "index", { intersect: false, axis: "y" }, false);
337+
if ((tooltipActive.length === 0) || (activePoints.length === 0)) {
338+
remove_tooltip_target();
339339
return;
340340
}
341341

342342
const index = activePoints[0].index;
343343
const label = sourceChart.data.labels[index];
344-
console.log(label);
345-
346344
const targetIndex = targetChart.data.labels.indexOf(label);
347-
if (targetIndex === -1) { return; } // label not found in the second graph
345+
if (targetIndex === -1) { return; }
348346

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;
349351

350352
targetChart.setActiveElements([{ datasetIndex: 0, index: targetIndex }]);
351-
targetChart.tooltip.setActiveElements([{ datasetIndex: 0, index: targetIndex }], { x: 0, y: 0 });
352-
targetChart.draw();
353-
});
353+
targetChart.tooltip.setActiveElements(
354+
[{ datasetIndex: 0, index: targetIndex }],
355+
{ x: centerX, y: canvasRect.top + relativeY }
356+
);
357+
targetChart.update();
358+
}
354359

355-
sourceChart.canvas.addEventListener("mouseleave", () => {
356-
remove_tooltip_target();
357-
});
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+
}
358386
}
359-
*/
360387

361388

362389
async function create_weekday_chart(firstDayOfWeek) {

scripts/main.js

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ function fill_empty_dates(data) {
140140
}
141141

142142

143-
function filter_pixels(numberOfDays) {
143+
async function filter_pixels(numberOfDays) {
144144
const lastPixelDate = new Date(current_data[current_data.length - 1].date);
145145
current_data = initial_data.filter(entry => {
146146
const entryDate = new Date(entry.date);
@@ -157,19 +157,25 @@ function filter_pixels(numberOfDays) {
157157
stats_content_container.style.display = "block";
158158

159159
fill_empty_dates(current_data);
160-
compute_tag_stats(current_data);
161-
compute_weekdays_stats(current_data);
162-
compute_months_stats(current_data);
163-
get_word_frequency(current_data, wordcloudOrderCount, minScore, searchTerm);
164160

165-
calculate_and_display_stats(current_data);
166-
create_mood_chart(current_data, averagingValue, showAverage, showYears);
167-
create_tag_frequency_chart(tagsPercentage, nbMaxTags);
168-
create_tag_score_chart(nbMaxTags);
169-
create_weekday_chart(png_settings.firstDayOfWeek);
170-
create_month_chart(seasonColors);
171-
create_word_frequency_section(current_data, nbMaxWords, nbMinCount, wordcloudPercentage, searchTerm);
172-
setup_calendar_frame();
161+
await Promise.all([
162+
calculate_and_display_stats(data),
163+
compute_tag_stats(current_data),
164+
compute_weekdays_stats(current_data),
165+
compute_months_stats(current_data),
166+
get_word_frequency(current_data, wordcloudOrderCount, minScore, searchTerm),
167+
168+
// Graphics
169+
create_mood_chart(current_data, averagingValue, showAverage, showYears),
170+
create_tag_frequency_chart(tagsPercentage, nbMaxTags),
171+
create_tag_score_chart(nbMaxTags),
172+
create_weekday_chart(png_settings.firstDayOfWeek),
173+
create_month_chart(seasonColors),
174+
create_word_frequency_section(current_data, nbMaxWords, nbMinCount, wordcloudPercentage, searchTerm),
175+
setup_calendar_frame(),
176+
]);
177+
178+
sync_tag_charts_hover();
173179
}
174180
}
175181

@@ -204,20 +210,24 @@ async function handle_file_upload(file) {
204210
await load_settings();
205211

206212
// Stats
207-
calculate_and_display_stats(data);
208-
compute_tag_stats(current_data);
209-
compute_weekdays_stats(current_data);
210-
compute_months_stats(current_data);
211-
get_word_frequency(current_data, wordcloudOrderCount, minScore, searchTerm);
212-
213-
// Graphics
214-
create_mood_chart(current_data, averagingValue, showAverage, showYears);
215-
create_tag_frequency_chart(tagsPercentage, nbMaxTags);
216-
create_tag_score_chart(nbMaxTags);
217-
create_weekday_chart(png_settings.firstDayOfWeek);
218-
create_month_chart(seasonColors);
219-
create_word_frequency_section(current_data, nbMaxWords, nbMinCount, wordcloudPercentage, searchTerm);
220-
setup_calendar_frame();
213+
await Promise.all([
214+
calculate_and_display_stats(data),
215+
compute_tag_stats(current_data),
216+
compute_weekdays_stats(current_data),
217+
compute_months_stats(current_data),
218+
get_word_frequency(current_data, wordcloudOrderCount, minScore, searchTerm),
219+
220+
// Graphics
221+
create_mood_chart(current_data, averagingValue, showAverage, showYears),
222+
create_tag_frequency_chart(tagsPercentage, nbMaxTags),
223+
create_tag_score_chart(nbMaxTags),
224+
create_weekday_chart(png_settings.firstDayOfWeek),
225+
create_month_chart(seasonColors),
226+
create_word_frequency_section(current_data, nbMaxWords, nbMinCount, wordcloudPercentage, searchTerm),
227+
setup_calendar_frame(),
228+
]);
229+
230+
sync_tag_charts_hover();
221231

222232

223233
// DEBUGGING
@@ -361,18 +371,21 @@ document.addEventListener("DOMContentLoaded", () => {
361371
tag_frequency_checkbox.addEventListener("change", (e) => {
362372
tagsPercentage = e.target.checked;
363373
create_tag_frequency_chart(tagsPercentage, nbMaxTags);
374+
sync_tag_charts_hover();
364375
});
365376

366377
input_nb_tags.addEventListener("input", (e) => {
367378
nbMaxTags = parseInt(e.target.value);
368379
create_tag_frequency_chart(tagsPercentage, nbMaxTags);
369380
create_tag_score_chart(nbMaxTags);
381+
sync_tag_charts_hover();
370382
});
371383

372384
select_tag_category.addEventListener("input", (e) => {
373385
tagCategory = e.target.value;
374386
create_tag_frequency_chart(tagsPercentage, nbMaxTags);
375387
create_tag_score_chart(nbMaxTags);
388+
sync_tag_charts_hover();
376389
});
377390

378391

0 commit comments

Comments
 (0)