HTML5 APIs - Geolocation, Canvas, and Local Storage 🌐🎨💾¶
Mentor's Note: HTML5 APIs are like superpowers for your web pages! They give your websites abilities that were once only possible with native apps - from finding user locations to creating stunning graphics and storing data locally! 🚀✨
📚 Educational Content: This comprehensive guide covers essential HTML5 APIs that enable modern web applications with location services, graphics, and data persistence.
🎯 Learning Objectives¶
By the end of this lesson, students will be able to:
- Implement Geolocation API to get user location
- Create graphics and animations with Canvas API
- Store and retrieve data using Local Storage and Session Storage
- Handle API errors and browser compatibility
- Build interactive applications using HTML5 APIs
🌟 The Scenario: Smart Weather App 🌤️¶
Mental Model for beginners: Think of HTML5 APIs as special tools that extend your website's capabilities! Imagine you're building a smart weather application... 🌈
- Location Detection: Geolocation API - Find user's current location
- Weather Visualization: Canvas API - Draw weather graphs and animations
- Settings Storage: Local Storage - Save user preferences
- Session Data: Session Storage - Track current weather session
- The Result: A fully functional weather app! ✅
📖 HTML5 APIs Overview¶
Why HTML5 APIs Matter:¶
- Enhanced Functionality: Access device features
- Better User Experience: More interactive applications
- Offline Capabilities: Store data locally
- Rich Graphics: Create visual content
- Modern Web Standards: Industry-standard capabilities
🗺️ Geolocation API¶
What is Geolocation?¶
The Geolocation API allows websites to request and receive the user's geographical position.
Key Concepts:¶
- Permission-based: User must grant access
- Multiple methods: GPS, WiFi, IP-based location
- Accuracy levels: Varies by method
- Privacy considerations: User consent required
Basic Geolocation Usage:¶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Geolocation Example</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.location-info {
background: #f0f8ff;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.coordinates {
font-family: monospace;
background: #e8e8e8;
padding: 10px;
border-radius: 4px;
}
.error {
background: #ffe6e6;
color: #d00;
padding: 10px;
border-radius: 4px;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #0056b3;
}
</style>
</head>
<body>
<h1>🗺️ Geolocation Demo</h1>
<button onclick="getLocation()">Get My Location</button>
<div id="result"></div>
<script>
function getLocation() {
const resultDiv = document.getElementById('result');
// Check if geolocation is supported
if (!navigator.geolocation) {
resultDiv.innerHTML = '<div class="error">❌ Geolocation is not supported by your browser</div>';
return;
}
resultDiv.innerHTML = '<div>🔄 Getting your location...</div>';
// Get current position
navigator.geolocation.getCurrentPosition(
// Success callback
function(position) {
const coords = position.coords;
const timestamp = new Date(position.timestamp);
resultDiv.innerHTML = `
<div class="location-info">
<h2>📍 Your Location Found!</h2>
<div class="coordinates">
<strong>Latitude:</strong> ${coords.latitude.toFixed(6)}<br>
<strong>Longitude:</strong> ${coords.longitude.toFixed(6)}<br>
<strong>Accuracy:</strong> ${coords.accuracy.toFixed(2)} meters<br>
<strong>Altitude:</strong> ${coords.altitude ? coords.altitude.toFixed(2) + ' meters' : 'Not available'}<br>
<strong>Altitude Accuracy:</strong> ${coords.altitudeAccuracy ? coords.altitudeAccuracy.toFixed(2) + ' meters' : 'Not available'}<br>
<strong>Heading:</strong> ${coords.heading ? coords.heading.toFixed(2) + '°' : 'Not available'}<br>
<strong>Speed:</strong> ${coords.speed ? (coords.speed * 3.6).toFixed(2) + ' km/h' : 'Not available'}<br>
<strong>Timestamp:</strong> ${timestamp.toLocaleString()}
</div>
</div>
`;
},
// Error callback
function(error) {
let errorMessage = '';
switch(error.code) {
case error.PERMISSION_DENIED:
errorMessage = '❌ User denied the request for Geolocation';
break;
case error.POSITION_UNAVAILABLE:
errorMessage = '❌ Location information is unavailable';
break;
case error.TIMEOUT:
errorMessage = '❌ The request to get location timed out';
break;
case error.UNKNOWN_ERROR:
errorMessage = '❌ An unknown error occurred';
break;
}
resultDiv.innerHTML = `<div class="error">${errorMessage}</div>`;
},
// Options
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
}
);
}
// Watch position (continuous tracking)
let watchId = null;
function startTracking() {
if (navigator.geolocation) {
watchId = navigator.geolocation.watchPosition(
function(position) {
console.log('New position:', position.coords);
},
function(error) {
console.error('Tracking error:', error);
}
);
}
}
function stopTracking() {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
}
}
</script>
</body>
</html>
Geolocation Options:¶
- enableHighAccuracy: More accurate but slower
- timeout: Maximum time to wait
- maximumAge: Cache duration for position
🎨 Canvas API¶
What is Canvas?¶
The Canvas API provides a way to draw graphics using JavaScript and HTML.
Key Concepts:¶
- 2D Context: Drawing surface
- Coordinate System: (0,0) at top-left
- Drawing Methods: Shapes, text, images
- Animation: Frame-by-frame rendering
Canvas Drawing Example:¶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Drawing Demo</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
.canvas-container {
border: 2px solid #333;
margin: 20px 0;
display: inline-block;
}
canvas {
display: block;
background: white;
}
.controls {
margin: 20px 0;
}
button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
.color-picker {
margin: 0 10px;
}
</style>
</head>
<body>
<h1>🎨 Canvas Drawing Demo</h1>
<div class="controls">
<button onclick="drawRectangle()">Draw Rectangle</button>
<button onclick="drawCircle()">Draw Circle</button>
<button onclick="drawLine()">Draw Line</button>
<button onclick="drawText()">Draw Text</button>
<button onclick="drawGradient()">Draw Gradient</button>
<button onclick="drawImage()">Draw Image</button>
<button onclick="clearCanvas()">Clear Canvas</button>
<button onclick="startAnimation()">Start Animation</button>
<button onclick="stopAnimation()">Stop Animation</button>
</div>
<div class="canvas-container">
<canvas id="myCanvas" width="800" height="400"></canvas>
</div>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let animationId = null;
let ballX = 50, ballY = 50, ballVX = 5, ballVY = 3;
// Draw Rectangle
function drawRectangle() {
ctx.fillStyle = '#007bff';
ctx.fillRect(50, 50, 200, 100);
ctx.strokeStyle = '#0056b3';
ctx.lineWidth = 3;
ctx.strokeRect(300, 50, 200, 100);
}
// Draw Circle
function drawCircle() {
ctx.beginPath();
ctx.arc(150, 250, 50, 0, 2 * Math.PI);
ctx.fillStyle = '#28a745';
ctx.fill();
ctx.beginPath();
ctx.arc(400, 250, 50, 0, 2 * Math.PI);
ctx.strokeStyle = '#dc3545';
ctx.lineWidth = 4;
ctx.stroke();
}
// Draw Line
function drawLine() {
ctx.beginPath();
ctx.moveTo(50, 350);
ctx.lineTo(750, 350);
ctx.strokeStyle = '#6c757d';
ctx.lineWidth = 2;
ctx.stroke();
// Draw arrow
ctx.beginPath();
ctx.moveTo(750, 350);
ctx.lineTo(740, 345);
ctx.lineTo(740, 355);
ctx.closePath();
ctx.fillStyle = '#6c757d';
ctx.fill();
}
// Draw Text
function drawText() {
ctx.font = 'bold 36px Arial';
ctx.fillStyle = '#333';
ctx.fillText('Canvas Text', 50, 100);
ctx.font = '24px Georgia';
ctx.strokeStyle = '#007bff';
ctx.lineWidth = 2;
ctx.strokeText('Outlined Text', 50, 150);
// Text with gradient
const gradient = ctx.createLinearGradient(0, 0, 400, 0);
gradient.addColorStop(0, '#ff0000');
gradient.addColorStop(0.5, '#00ff00');
gradient.addColorStop(1, '#0000ff');
ctx.font = 'bold 48px Arial';
ctx.fillStyle = gradient;
ctx.fillText('Gradient Text!', 50, 250);
}
// Draw Gradient
function drawGradient() {
// Linear gradient
const linearGradient = ctx.createLinearGradient(500, 50, 700, 150);
linearGradient.addColorStop(0, '#ff0000');
linearGradient.addColorStop(0.5, '#00ff00');
linearGradient.addColorStop(1, '#0000ff');
ctx.fillStyle = linearGradient;
ctx.fillRect(500, 50, 200, 100);
// Radial gradient
const radialGradient = ctx.createRadialGradient(600, 250, 20, 600, 250, 80);
radialGradient.addColorStop(0, '#ffff00');
radialGradient.addColorStop(0.5, '#ff8800');
radialGradient.addColorStop(1, '#ff0000');
ctx.fillStyle = radialGradient;
ctx.beginPath();
ctx.arc(600, 250, 80, 0, 2 * Math.PI);
ctx.fill();
}
// Draw Image
function drawImage() {
const img = new Image();
img.onload = function() {
ctx.drawImage(img, 50, 180, 150, 100);
// Draw part of image
ctx.drawImage(img, 100, 50, 100, 100, 250, 180, 100, 100);
};
img.src = 'https://picsum.photos/seed/canvas-demo/300/200.jpg';
}
// Clear Canvas
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// Animation
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw bouncing ball
ctx.beginPath();
ctx.arc(ballX, ballY, 20, 0, 2 * Math.PI);
ctx.fillStyle = '#007bff';
ctx.fill();
// Update position
ballX += ballVX;
ballY += ballVY;
// Bounce off walls
if (ballX + 20 > canvas.width || ballX - 20 < 0) {
ballVX = -ballVX;
}
if (ballY + 20 > canvas.height || ballY - 20 < 0) {
ballVY = -ballVY;
}
animationId = requestAnimationFrame(animate);
}
function startAnimation() {
if (!animationId) {
animate();
}
}
function stopAnimation() {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
}
// Interactive drawing
let isDrawing = false;
let lastX = 0;
let lastY = 0;
canvas.addEventListener('mousedown', function(e) {
isDrawing = true;
const rect = canvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
});
canvas.addEventListener('mousemove', function(e) {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.stroke();
lastX = x;
lastY = y;
});
canvas.addEventListener('mouseup', function() {
isDrawing = false;
});
canvas.addEventListener('mouseout', function() {
isDrawing = false;
});
</script>
</body>
</html>
💾 Web Storage API¶
What is Web Storage?¶
Web Storage provides mechanisms for storing data locally in the browser.
Two Types:¶
- Local Storage: Persistent data (no expiration)
- Session Storage: Data for current session only
Storage Example:¶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Storage Demo</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.storage-demo {
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.form-group {
margin: 15px 0;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, textarea {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
.storage-info {
background: #e8f5e8;
padding: 15px;
border-radius: 4px;
margin: 10px 0;
}
.error {
background: #ffe6e6;
color: #d00;
padding: 10px;
border-radius: 4px;
}
.data-item {
background: white;
padding: 10px;
margin: 5px 0;
border-radius: 4px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<h1>💾 Web Storage Demo</h1>
<div class="storage-demo">
<h2>📝 User Preferences Form</h2>
<div class="form-group">
<label for="username">Username:</label>
<input type="text" id="username" placeholder="Enter your username">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" placeholder="Enter your email">
</div>
<div class="form-group">
<label for="theme">Theme:</label>
<select id="theme">
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="blue">Blue</option>
</select>
</div>
<div class="form-group">
<label for="notes">Notes:</label>
<textarea id="notes" rows="4" placeholder="Enter your notes"></textarea>
</div>
<button onclick="saveToLocalStorage()">💾 Save to Local Storage</button>
<button onclick="saveToSessionStorage()">📋 Save to Session Storage</button>
<button onclick="loadFromStorage()">📂 Load from Storage</button>
<button onclick="clearStorage()">🗑️ Clear Storage</button>
<button onclick="showStorageInfo()">ℹ️ Show Storage Info</button>
</div>
<div id="result"></div>
<script>
// Save to Local Storage
function saveToLocalStorage() {
try {
const userData = {
username: document.getElementById('username').value,
email: document.getElementById('email').value,
theme: document.getElementById('theme').value,
notes: document.getElementById('notes').value,
timestamp: new Date().toISOString()
};
localStorage.setItem('userPreferences', JSON.stringify(userData));
showResult('✅ Data saved to Local Storage!', 'success');
} catch (error) {
showResult('❌ Error saving to Local Storage: ' + error.message, 'error');
}
}
// Save to Session Storage
function saveToSessionStorage() {
try {
const sessionData = {
username: document.getElementById('username').value,
email: document.getElementById('email').value,
theme: document.getElementById('theme').value,
notes: document.getElementById('notes').value,
timestamp: new Date().toISOString()
};
sessionStorage.setItem('sessionData', JSON.stringify(sessionData));
showResult('✅ Data saved to Session Storage!', 'success');
} catch (error) {
showResult('❌ Error saving to Session Storage: ' + error.message, 'error');
}
}
// Load from Storage
function loadFromStorage() {
try {
// Try Local Storage first
let userData = localStorage.getItem('userPreferences');
if (userData) {
const data = JSON.parse(userData);
document.getElementById('username').value = data.username || '';
document.getElementById('email').value = data.email || '';
document.getElementById('theme').value = data.theme || 'light';
document.getElementById('notes').value = data.notes || '';
showResult('✅ Data loaded from Local Storage!', 'success');
} else {
// Try Session Storage
let sessionData = sessionStorage.getItem('sessionData');
if (sessionData) {
const data = JSON.parse(sessionData);
document.getElementById('username').value = data.username || '';
document.getElementById('email').value = data.email || '';
document.getElementById('theme').value = data.theme || 'light';
document.getElementById('notes').value = data.notes || '';
showResult('✅ Data loaded from Session Storage!', 'success');
} else {
showResult('ℹ️ No data found in storage', 'info');
}
}
} catch (error) {
showResult('❌ Error loading from storage: ' + error.message, 'error');
}
}
// Clear Storage
function clearStorage() {
localStorage.clear();
sessionStorage.clear();
// Clear form
document.getElementById('username').value = '';
document.getElementById('email').value = '';
document.getElementById('theme').value = 'light';
document.getElementById('notes').value = '';
showResult('🗑️ Storage cleared!', 'success');
}
// Show Storage Info
function showStorageInfo() {
const info = [];
// Local Storage info
info.push('<h3>📦 Local Storage</h3>');
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
info.push(`<div class="data-item"><strong>${key}:</strong> ${value}</div>`);
}
// Session Storage info
info.push('<h3>📋 Session Storage</h3>');
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i);
const value = sessionStorage.getItem(key);
info.push(`<div class="data-item"><strong>${key}:</strong> ${value}</div>`);
}
// Storage quota
if ('storage' in navigator && 'estimate' in navigator.storage) {
navigator.storage.estimate().then(function(estimate) {
info.push(`<h3>💾 Storage Quota</h3>`);
info.push(`<div class="storage-info">`);
info.push(`<strong>Usage:</strong> ${(estimate.usage / 1024 / 1024).toFixed(2)} MB<br>`);
info.push(`<strong>Quota:</strong> ${(estimate.quota / 1024 / 1024).toFixed(2)} MB<br>`);
info.push(`<strong>Available:</strong> ${((estimate.quota - estimate.usage) / 1024 / 1024).toFixed(2)} MB`);
info.push(`</div>`);
document.getElementById('result').innerHTML = info.join('');
});
} else {
document.getElementById('result').innerHTML = info.join('');
}
}
// Show result message
function showResult(message, type) {
const resultDiv = document.getElementById('result');
const className = type === 'error' ? 'error' : 'storage-info';
resultDiv.innerHTML = `<div class="${className}">${message}</div>`;
}
// Auto-save functionality
let autoSaveTimer;
function setupAutoSave() {
const inputs = document.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
input.addEventListener('input', function() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(function() {
saveToLocalStorage();
showResult('💾 Auto-saved!', 'success');
}, 2000);
});
});
}
// Load data on page load
window.addEventListener('load', function() {
loadFromStorage();
setupAutoSave();
});
// Storage event listener (for cross-tab communication)
window.addEventListener('storage', function(e) {
console.log('Storage changed:', e);
if (e.key === 'userPreferences') {
showResult('🔄 Data updated in another tab!', 'info');
}
});
</script>
</body>
</html>
🔄 Storage Event Handling¶
Cross-Tab Communication:¶
// Listen for storage changes in other tabs
window.addEventListener('storage', function(event) {
console.log('Storage changed:', event);
console.log('Key:', event.key);
console.log('Old value:', event.oldValue);
console.log('New value:', event.newValue);
console.log('URL:', event.url);
if (event.key === 'userPreferences') {
// Reload preferences
loadUserPreferences();
}
});
📊 Storage Limits and Best Practices¶
Storage Limits:¶
- Local Storage: ~5-10 MB per domain
- Session Storage: ~5-10 MB per domain
- Browser dependent: Varies by browser
Best Practices:¶
- Check availability: Test for support
- Handle errors: Use try-catch blocks
- Data validation: Validate stored data
- Security: Don't store sensitive data
- Performance: Minimize storage operations
🧪 Quick Quiz¶
Test Your Knowledge!¶
Question 1: Which method gets the user's current position?
- A) navigator.getPosition()
- B) navigator.geolocation.getCurrentPosition()
- C) navigator.location.get()
- D) geolocation.getCurrentPosition()
Question 2: What is the default origin point for Canvas coordinates? - A) Center of canvas - B) Bottom-left corner - C) Top-left corner - D) Top-right corner
Question 3: Which storage type persists after browser closes? - A) Session Storage - B) Local Storage - C) Memory Storage - D) Cache Storage
Question 4: What does ctx.arc() create?
- A) A rectangle
- B) A circle or arc
- C) A line
- D) A triangle
Question 5: How do you clear a canvas?
- A) canvas.clear()
- B) ctx.clearRect()
- C) ctx.empty()
- D) canvas.reset()
💻 Practice Exercises¶
Exercise 1: Location-Based Weather App¶
Create a weather app that: 1. Gets user's location 2. Shows coordinates 3. Displays weather based on location 4. Saves user preferences
Exercise 2: Canvas Drawing Game¶
Build a drawing game with: 1. Different drawing tools 2. Color selection 3. Clear and save functionality 4. Shape drawing tools
Exercise 3: Personal Notes App¶
Create a notes application: 1. Save notes to local storage 2. Organize notes by categories 3. Search functionality 4. Export/import features
🚀 Common Mistakes & Solutions¶
Mistake 1: Not checking API support¶
// ❌ Wrong
navigator.geolocation.getCurrentPosition(success, error);
// ✅ Correct
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
console.log('Geolocation not supported');
}
Mistake 2: Not handling storage errors¶
// ❌ Wrong
localStorage.setItem('data', JSON.stringify(largeObject));
// ✅ Correct
try {
localStorage.setItem('data', JSON.stringify(largeObject));
} catch (error) {
console.error('Storage quota exceeded');
}
Mistake 3: Canvas context issues¶
// ❌ Wrong
const canvas = document.getElementById('canvas');
canvas.fillRect(10, 10, 50, 50);
// ✅ Correct
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillRect(10, 10, 50, 50);
🌟 Real-World Examples¶
Example 1: Location-Based Services¶
- Food delivery: Find nearest restaurants
- Ride sharing: Track driver location
- Weather apps: Local weather information
- Social media: Location-based posts
Example 2: Canvas Applications¶
- Photo editors: Image manipulation
- Games: 2D game graphics
- Charts: Data visualization
- Drawing apps: Creative tools
Example 3: Storage Solutions¶
- Shopping carts: Save cart items
- User preferences: Theme settings
- Offline apps: Cache data
- Form data: Auto-save functionality
📋 Implementation Checklist¶
Geolocation Implementation:¶
- Check browser support
- Handle user permissions
- Implement error handling
- Consider privacy implications
- Test on different devices
Canvas Implementation:¶
- Get 2D context
- Handle responsive sizing
- Optimize drawing operations
- Implement animations properly
- Consider accessibility
Storage Implementation:¶
- Choose appropriate storage type
- Handle storage limits
- Implement error handling
- Validate stored data
- Consider security implications
🎯 Summary¶
HTML5 APIs provide powerful capabilities for modern web applications:
Key Takeaways:¶
- Geolocation: Access user location with permission
- Canvas: Create graphics and animations
- Storage: Store data locally in browser
- Error Handling: Always handle API errors
- Browser Support: Check for API availability
Next Steps:¶
- Practice with real-world projects
- Explore advanced API features
- Learn about other HTML5 APIs
- Build complete applications
Remember:¶
- User Privacy: Always respect user permissions
- Performance: Optimize API usage
- Compatibility: Test across browsers
- Security: Protect user data
🔗 Additional Resources¶
Documentation:¶
Tutorials:¶
Tools:¶
"HTML5 APIs transform the web from static pages to interactive applications that rival native software!" 🚀✨