Sahib Update
How Qibla Calculation & Compass Work
1. Qibla Direction Calculation
Library Used
- adhan — JavaScript library for Islamic calculations
How It Works
const coordinates = new Coordinates(latitude, longitude);
const qiblaAngle = Qibla(coordinates); // Returns angle in degrees (0-360)
2. Device Heading (Compass)
Library Used
- expo-location — Expo’s location services
How It Works
Location.watchHeadingAsync((heading) => {
const headingValue = heading.trueHeading > 0
? heading.trueHeading // True North (GPS-based)
: heading.magHeading; // Magnetic North (compass-based)
setDeviceHeading(headingValue); // 0-360 degrees
});
- Listens to the device’s magnetometer/compass
- Returns the device’s heading (0–360°)
- trueHeading: GPS-based (more accurate, requires GPS)
- magHeading: magnetic compass (works without GPS)
3. Compass Rotation Formula
targetRotation = -deviceHeading
currentNormalized = normalizeAngle(currentRotation) // 0-360
targetNormalized = normalizeAngle(targetRotation) // 0-360
diff = targetNormalized - currentNormalized
if (diff > 180) diff -= 360 // Go the other way
if (diff < -180) diff += 360 // Go the other way
finalTarget = currentRotation + diff
Why negative?
- When device points North (0°), compass should show North at top (0° rotation)
- When device rotates 90° East, compass rotates -90° to keep North at top
4. Visual Display
Compass Circle
- Rotates with device movement
- Formula: rotate(-deviceHeading)
- Keeps North at the top visually
Qibla Arrow
- Stays fixed, pointing to qibla direction
- Formula: rotation = qiblaDirection (e.g., 58°)
- Shows the direction to Mecca relative to the compass
Design patterns in prayer-times service
1. Template Method Pattern
export interface PrayerTimeInput {
coordinates: Coordinates;
date?: Date;
timezone: string;
format?: string;
adjustments?: PrayerAdjustments;
}
export interface PrayerTimesResult {
fajr: Date;
sunrise: Date;
dhuhr: Date;
asr: Date;
maghrib: Date;
isha: Date;
formatted?: FormattedPrayerTimes;
}
export interface FormattedPrayerTimes {
fajr: string;
sunrise: string;
dhuhr: string;
asr: string;
maghrib: string;
isha: string;
}
// Base class defines the template
abstract class PrayerTimeCalculator {
public calculate(input: PrayerTimeInput): PrayerTimesResult {
// Step 1: Prepare (subclass implements)
const params = this.prepareCalculationParameters(input);
// Step 2: Apply adjustments (subclass implements)
const adjusted = this.applyAdjustments(params, input.adjustments);
// Step 3: Calculate (subclass implements)
const rawTimes = this.calculateRawPrayerTimes(input, adjusted);
// Step 4 & 5: Common steps (base class handles)
const timezoneAware = this.convertToTimezone(rawTimes, input.timezone);
const formatted = this.formatPrayerTimes(timezoneAware, input.timezone);
return { ...timezoneAware, formatted };
}
}