Skip to content

Commit 2b69c50

Browse files
committed
analytics
1 parent 3ebebad commit 2b69c50

File tree

5 files changed

+143
-8
lines changed

5 files changed

+143
-8
lines changed

index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
<meta name="description" content="Portfolio of Gabor Csapo showcasing his projects, experiences, and expertise in IoT, Urbanism, and Data Science.">
77
<title>Gabor Csapo - AI | Evaluation | Data</title>
88

9+
<!-- Google tag (gtag.js) -->
10+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-4XDKY642L6"></script>
11+
<script>
12+
window.dataLayer = window.dataLayer || [];
13+
function gtag(){dataLayer.push(arguments);}
14+
gtag('js', new Date());
15+
16+
gtag('config', 'G-4XDKY642L6');
17+
</script>
18+
919
<link rel="preconnect" href="https://fonts.googleapis.com">
1020
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
1121
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Syne:wght@400..800&display=swap" rel="stylesheet">

src/js/heroAnimation.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,17 @@ export function initAnimation() {
672672

673673
currentPaletteIndex = (currentPaletteIndex + 1) % artPalettes.length;
674674
currentPalette = artPalettes[currentPaletteIndex];
675+
676+
// Track color switching with Google Analytics
677+
if (typeof gtag !== 'undefined') {
678+
gtag('event', 'color_switch', {
679+
event_category: 'Hero Animation',
680+
event_label: currentPalette.name,
681+
palette_index: currentPaletteIndex,
682+
previous_palette: artPalettes[(currentPaletteIndex - 1 + artPalettes.length) % artPalettes.length].name,
683+
interaction_method: 'click'
684+
});
685+
}
675686
// Don't change bgColor or circle colors immediately - wait for texture to be ready
676687

677688
// Generate new grain texture with updated palette
@@ -830,6 +841,17 @@ export function initAnimation() {
830841

831842
currentPaletteIndex = (currentPaletteIndex + 1) % artPalettes.length;
832843
currentPalette = artPalettes[currentPaletteIndex];
844+
845+
// Track programmatic color switching with Google Analytics
846+
if (typeof gtag !== 'undefined') {
847+
gtag('event', 'color_switch', {
848+
event_category: 'Hero Animation',
849+
event_label: currentPalette.name,
850+
palette_index: currentPaletteIndex,
851+
previous_palette: artPalettes[(currentPaletteIndex - 1 + artPalettes.length) % artPalettes.length].name,
852+
interaction_method: 'programmatic'
853+
});
854+
}
833855
// Don't change bgColor or circle colors immediately - wait for texture to be ready
834856

835857
// Generate new grain texture with updated palette

src/js/main.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function initializeApp() {
1313
initColorPicker();
1414
initSmoothScrolling();
1515
initScrollAnimations();
16+
initSocialLinkTracking();
1617

1718
// Initialize animation after p5 is loaded
1819
loadP5Animation();
@@ -81,9 +82,47 @@ function initScrollAnimations() {
8182
// No static elements need animation observers currently
8283
}
8384

85+
function initSocialLinkTracking() {
86+
// Track clicks on all social/contact links
87+
const socialLinks = document.querySelectorAll('.contact-minimal a');
88+
89+
socialLinks.forEach(link => {
90+
link.addEventListener('click', function(event) {
91+
if (typeof gtag !== 'undefined') {
92+
const linkText = this.textContent.trim();
93+
const linkUrl = this.href;
94+
const isExternal = linkUrl.startsWith('http') && !linkUrl.includes(window.location.hostname);
95+
96+
gtag('event', 'social_link_click', {
97+
event_category: 'Social Links',
98+
event_label: linkText,
99+
link_url: linkUrl,
100+
link_type: isExternal ? 'external' : 'internal',
101+
destination: linkText.toLowerCase()
102+
});
103+
104+
// For external links, add a small delay to ensure tracking
105+
if (isExternal && event.target.target === '_blank') {
106+
// No delay needed for _blank links as they open in new window
107+
}
108+
}
109+
});
110+
});
111+
}
112+
84113
function initAnalytics() {
85-
// Analytics placeholder - add Google Analytics script to HTML if needed
86-
console.log('Analytics initialized');
114+
// Google Analytics is now loaded via gtag in HTML
115+
if (typeof gtag !== 'undefined') {
116+
console.log('Google Analytics initialized');
117+
118+
// Track page view
119+
gtag('event', 'page_view', {
120+
page_title: document.title,
121+
page_location: window.location.href
122+
});
123+
} else {
124+
console.log('Google Analytics not available');
125+
}
87126
}
88127

89128
// Utility functions

src/js/timelineComponent.js

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ function renderContent() {
183183
}
184184

185185
// Navigate to chapter with animation
186-
function navigateToChapter(newIndex) {
186+
function navigateToChapter(newIndex, interactionMethod = 'click') {
187187
if (isTransitioning || newIndex === activeChapter) return;
188188

189189
// Hide the hint after first navigation
@@ -194,6 +194,19 @@ function navigateToChapter(newIndex) {
194194

195195
isTransitioning = true;
196196
const direction = newIndex > activeChapter ? 'next' : 'prev';
197+
198+
// Track timeline navigation with Google Analytics
199+
if (typeof gtag !== 'undefined') {
200+
const chapterName = chapters[newIndex]?.title || `Chapter ${newIndex}`;
201+
gtag('event', 'timeline_navigation', {
202+
event_category: 'Timeline',
203+
event_label: chapterName,
204+
chapter_index: newIndex,
205+
direction: direction,
206+
previous_chapter: activeChapter,
207+
interaction_method: interactionMethod
208+
});
209+
}
197210

198211
// Calculate timeline position
199212
const timelineElement = document.querySelector('.timeline-section');
@@ -260,11 +273,11 @@ function navigateToChapter(newIndex) {
260273
}
261274

262275
// Navigate with buttons
263-
function navigate(direction) {
276+
function navigate(direction, interactionMethod = 'button') {
264277
const newIndex = direction === 'next'
265278
? Math.min(activeChapter + 1, chapters.length - 1)
266279
: Math.max(activeChapter - 1, 0);
267-
navigateToChapter(newIndex);
280+
navigateToChapter(newIndex, interactionMethod);
268281
}
269282

270283
// Initialize event listeners
@@ -285,10 +298,13 @@ function initEventListeners() {
285298

286299
// Keyboard navigation
287300
document.addEventListener('keydown', (e) => {
288-
if (e.key === 'ArrowLeft') navigate('prev');
289-
if (e.key === 'ArrowRight') navigate('next');
301+
if (e.key === 'ArrowLeft') navigate('prev', 'keyboard');
302+
if (e.key === 'ArrowRight') navigate('next', 'keyboard');
290303
});
291304

305+
// Touch gesture navigation
306+
initTouchGestures();
307+
292308
// Handle resize
293309
let resizeTimeout;
294310
window.addEventListener('resize', () => {
@@ -299,6 +315,54 @@ function initEventListeners() {
299315
});
300316
}
301317

318+
// Touch gesture support
319+
function initTouchGestures() {
320+
if (!timelineSection) return;
321+
322+
let touchStartX = 0;
323+
let touchStartY = 0;
324+
let touchEndX = 0;
325+
let touchEndY = 0;
326+
327+
// Minimum distance for a swipe to register (in pixels)
328+
const minSwipeDistance = 50;
329+
// Maximum vertical movement allowed for horizontal swipe
330+
const maxVerticalDeviation = 100;
331+
332+
// Touch start
333+
timelineSection.addEventListener('touchstart', (e) => {
334+
touchStartX = e.touches[0].clientX;
335+
touchStartY = e.touches[0].clientY;
336+
}, { passive: true });
337+
338+
// Touch end
339+
timelineSection.addEventListener('touchend', (e) => {
340+
touchEndX = e.changedTouches[0].clientX;
341+
touchEndY = e.changedTouches[0].clientY;
342+
handleSwipe();
343+
}, { passive: true });
344+
345+
// Handle swipe gesture
346+
function handleSwipe() {
347+
const deltaX = touchEndX - touchStartX;
348+
const deltaY = Math.abs(touchEndY - touchStartY);
349+
350+
// Check if this was primarily a horizontal swipe
351+
if (Math.abs(deltaX) > minSwipeDistance && deltaY < maxVerticalDeviation) {
352+
// Prevent navigation if already transitioning
353+
if (isTransitioning) return;
354+
355+
// Swipe right (positive deltaX) = go to previous chapter
356+
// Swipe left (negative deltaX) = go to next chapter
357+
if (deltaX > 0) {
358+
navigate('prev', 'swipe');
359+
} else {
360+
navigate('next', 'swipe');
361+
}
362+
}
363+
}
364+
}
365+
302366
// Main initialization function
303367
export function initTimelineComponent() {
304368
console.log('Initializing timeline component...');

src/styles/main.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ p, h1, h2, h3, h4, h5, h6 {
862862

863863
.timeline-label {
864864
font-size: var(--text-xs);
865-
opacity: 0.4;
865+
opacity: 0;
866866
top: 2rem;
867867
}
868868

0 commit comments

Comments
 (0)