[Huawei Developers] muraliameakula:
Article Introduction

In this article we will develop Qibla finder application for Huawei Smart Watch device using Huawei DevEco Studio (HarmonyOS). We will fetch Location and Compass API’s of HarmonyOS JS language to develop Application.

1. Create New Project

Let’s create Smart Watch Project and choosing ability template, Wearable and Empty Feature Ability (JS)

Define project name, package name and relevant directory where you want to save your project.

2. Preparing Files and Permission

Let’s first add images and permissions which we will use for project.

All project images will be under common/images folder, check below screenshot.

Next we need to add permissions for Internet and Location under config.json file.

"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.LOCATION",
"reason": "get Qibla direction",
"usedScene": {
"ability": [
"default"
],
"when": "always"
}
}
]

3. Compass Development

In Compass screen development we will cover Location permission, Location fetching, location error and compass degree value.

Let’s start development without wasting more time.

Styling:

index.css:

.stack {
width: 454px;
height: 454px;
justify-content: center;
background-color: whitesmoke;
}
.container {
background-color: whitesmoke;
}
.compass-container {
display: flex;
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
width: 454px;
height: 454px;
background-color: whitesmoke;
}
.container-location-loading{
background-image: url('/common/images/background.png');
flex-direction: column;
padding-top: 0px;
padding-bottom: 0px;
height: 456px;
width: 456px;
}
.error-container {
background-image: url('/common/images/background.png');
padding-top: 0px;
padding-bottom: 0px;
height: 456px;
width: 100%;
}
.location_loading{
object-fit:contain;
height: 456px;
width: 292px;
}
.column{
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
}
.needle{
left: 0px;
top: 0px;
width: 220px;
height: 220px;
background-color: transparent;
z-index:99;
}
.compass, .compass2{
left: 0px;
top: 0px;
width: 220px;
height: 220px;
background-color: transparent;
z-index:98;
}
.qibla_style{
display: flex;
left: 0px;
top: 0px;
width: 220px;
height: 220px;
background-color: transparent;
z-index:100000;
}

.error_title{
display: flex;
color: red;
width: 100%;
height: 100%;
justify-content: center;
align-content: center;
text-align: center;
font-size: 24px;
}
.button-container{
display: flex;
flex-direction: row;
justify-content: center;
align-content: space-around;
position: absolute;
bottom: 10px;
}

Layout:

Location Loading Animation:

<stack if="{{isLocationLoading === true && isLocationError === false}}" class="container-location-loading">
<image src="../../common/images/location_animation.gif" class="location_loading" />
</stack>

Location Loading Output:

Location Error and Retry:

<stack if="{{isLocationLoading === false && isLocationError === true}}" class="error-container">
<text class="error_title">Location not fetch. Try again</text>
<div class="button-container">
<button type="circle" icon="/common/images/exit.png" onclick="exit"></button>
<button type="circle" icon="/common/images/refresh.png" onclick="retry"></button>
</div>
</stack>

Location Error Output:

Compass UI:

<stack class="compass-container" if="{{isLocationLoading === false && isLocationError === false}}">

<stack class="compass" style="transform:{{compass_transform}}">
<div class="needle" style="transform:{{needle_transform}}">
<image src="/common/images/needle.png"></image>
</div>
<div class="compass" >
<image src="/common/images/compass.png"></image>
</div>
</stack>

<div class="qibla_style">
<image src="/common/images/qibla.png"></image>
</div>
</stack>

Compass UI Output:

JS code:

Structural - Code:

import sensor from '@system.sensor';
import brightness from '@system.brightness';
import geolocation from '@system.geolocation';
import app from '@system.app';
export default {}

Data:

data: {
compass_transform: "rotate(0deg)",
needle_transform: "rotate(0deg)",
isLocationLoading: true,
isLocationError: false,
}

Common - Code:

onReady() {
this.setBrightnessKeepScreenOn();
},

onInit() {
this.initLocationCompass();
},

exit(){
app.terminate();
},

retry(){
this.isLocationLoading = true;
this.isLocationError = false;
this.initLocationCompass();
},

onDestroy() {
sensor.unsubscribeCompass();
},

// Setting the screen to be steady on
setBrightnessKeepScreenOn: function () {
brightness.setKeepScreenOn({
keepScreenOn: true,
success: function () {
console.log("handling set keep screen on success")
},
fail: function (data, code) {
console.log("handling set keep screen on fail, code:" + code);
}
});
},

onBackPress() {
sensor.unsubscribeCompass();
}

Location Fetching - Code:

initLocationCompass(){
var _this = this;
this.locationLoading().then(result => {
console.info("Location: " + result);
_this.loadCompass(result);
_this.isLocationLoading = false;
_this.isLocationError = false;
}, error => {
console.info("Location: error ->" + error);
_this.isLocationLoading = false;
_this.isLocationError = true;
});
},

locationLoading() {
return new Promise(function (resolve, reject) {
return geolocation.getLocation({
success: function (data) {
console.log('success get location data. latitude:' + data.latitude + 'long:' + data.longitude);
return resolve({
latitude: data.latitude,
longitude: data.longitude
});
},
fail: function (data, code) {
console.log('fail to get location. code:' + code + ', data:' + data);
return reject({
error: 'fail to get location. code:' + code + ', data:' + data
});
},
});
});
},

Compass - Code:

loadCompass(coordinates = {
latitude: 24.7136,
longitude: 46.6753
}) {

var _this = this;
var qiblaDirection = parseFloat(this.qibla(coordinates));
console.log("compass: qiblaDirection: " + qiblaDirection);
_this.needle_transform = "rotate(" + qiblaDirection + "deg)";
sensor.subscribeCompass({
success: function (ret) {
var direction = ret.direction;
var compassDirection = (360 - direction);
_this.compass_transform = "rotate(" + compassDirection + "deg)";
console.log("compass: compassDirection: " + direction);
},
fail: function (data, code) {
console.error('compass: subscribe compass fail, code: ' + code + ', data: ' + data);
},
});
},

Qibla Direction - Code:

qibla(coordinates) {
const makkah = {
latitude: 21.42252,
longitude: 39.82621
};

const term1 = Math.sin(this.degreesToRadians(makkah.longitude) - this.degreesToRadians(coordinates.longitude));
const term2 = Math.cos(this.degreesToRadians(coordinates.latitude)) * Math.tan(this.degreesToRadians(makkah.latitude));
const term3 = Math.sin(this.degreesToRadians(coordinates.latitude)) * Math.cos(this.degreesToRadians(makkah.longitude) - this.degreesToRadians(coordinates.longitude));
const angle = Math.atan2(term1, term2 - term3);
return this.unwindAngle(this.radiansToDegrees(angle));
},

degreesToRadians(degrees) {
return degrees * Math.PI / 180.0;
},

radiansToDegrees(radians) {
return radians * 180.0 / Math.PI;
},

normalizeToScale(number, max) {
return number - max * Math.floor(number / max);
},

unwindAngle(angle) {
return this.normalizeToScale(angle, 360.0);
},

Compass Screen Notes:

To manage Layout, we need to use <stack> to overlap UI component in layers. First we need to fetch location data and identify the Qibla direction in degree. And call Compass JS API to get compass degree and manage the UI accordingly.

4. Result

Tips and Tricks:

Requesting some data from internet, you must need to add Internet permission in config.json file.

Fetching Location data, you must need to add Internet Permission in config.json file.

Use Dev Eco Studio Previewer to check the screen layout and design. Previewer is developer friendly to Hot release changes on fly.

For better management of big application it’s a good practice to centralize you common scripts and common style in common folder. Add images folder for complete application images.

In JS script when you make some variable, in callback functions you can store the reference of this to some variable and then call reference variable. Like var _this = this.

References:

HarmonyOS JS API Official Documentation: click here

Geographic Location Documentation: click here

Sensor Documentation: click here

Conclusion:

Developers can able to fetch user location data and compass data to make Qibla finder application. While developing application for HarmonyOS developer can get benefit for both JS and JAVA language.

Original Source