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!" ๐โจ