历时半年整理出了十多万字的学习笔记,目前依旧在更新
欢迎点赞和支持~🥳🥳🥳
博客
主要运用技术: css3旋转和H5定位配合js实现
因为PC端没有陀螺仪,H5的GetCurrentPosition定位自己玩还要翻墙,所以我只得用移动端过下瘾。我用的是Android机,所以没有兼容IO。
写在前面
- 首先要开发这种页面需要你手机与你的电脑在一个局域网内,你还要一个服务器。我用WampServer64位腾讯管家里下的,现在不需要改服务器里的文件,直接可以用,其余的请自行百度,但一定不要在你需要用服务器打开的文件出现中文文件夹,答应我!
- 开发的这个指南针(实际上是指北的,姑且这么叫吧)其实并不准,是非常的不准,常常是与手机自带的指南针对准后,没过一会就偏了个40多度,定位就别想了。其实准的就是IOS的定位了,它有专门监听与正北方向的角度偏差,并实时调整。
- 定位自己经纬度的方法目前最方便的只有API了;建议用腾讯地图的,响应快,可以定位到市,但一天请求不了多少次,好像是5次吧;所以当你请求到了位置,就复制下来,答应我!
- 仿写的是华为手机自带的指南针
废话讲完,惯例先来个图(手机浏览器上打开的)
html部分
<div class="show">
<div class="wrapper">
<div class="box">
<div class="text">
<div class="direction-angle">西北 123°</div>
<div class="latitude">北纬 <span>123°5'23"</span></div>
<div class="longitude">东经 <span> 123°5'23"</span></div>
</div>
<!-- 指针 -->
<div class="point"></div>
<!-- 表盘 -->
<div class="dial">
<!-- 刻度 -->
<div class="scale">
<ul>
<!-- 自己生成-->
<li>*100
<li>*80
</ul>
</div>
<!-- 数字 -->
<div class="num">
<ul>
<li>0</li>
<li>20</li>
<li>40</li>
<li>60</li>
<li>80</li>
<li>100</li>
<li>120</li>
<li>140</li>
<li>160</li>
<li>180</li>
<li>200</li>
<li>220</li>
<li>240</li>
<li>260</li>
<li>280</li>
<li>300</li>
<li>320</li>
<li>340</li>
</ul>
<div class="sign"></div>
<div class=" direction north"><span>北</span></div>
<div class=" direction east"><span>东</span></div>
<div class=" direction south"><span>南</span></div>
<div class=" direction western"><span>西</span></div>
</div>
</div>
<!-- 中心水平仪 -->
<div class="gradienter-in"></div>
</div>
<!-- 第二页水平仪 -->
<div class="gradienter-out">
<span>
<div>12°</div>
</span>
</div>
</div>
</div>
css部分
* {
padding: 0px;
margin: 0px;
list-style: none;
}
:root,
body {
height: 100%;
}
body {
height: 100%;
display: flex;
justify-content: center;
}
.show {
height: 95%;
width: 350px;
transform: translate3D(0px, 20px, 0px);
}
.wrapper {
position: relative;
width: 700px;
height: 100%;
display: flex;
}
/* 第二页水平仪 */
.wrapper .gradienter-out {
position: relative;
height: 100%;
width: 350px;
}
.wrapper .gradienter-out span {
position: absolute;
left: calc(50% - 50px);
top: calc(50% - 50px);
height: 100px;
width: 100px;
border-radius: 50%;
}
.wrapper .gradienter-out span div {
position: absolute;
height: 50px;
width: 100px;
top: calc(50% - 25px);
text-align: center;
line-height: 50px;
font-size: 30px;
font-weight: bold;
transform-origin: center center;
}
/* 第一页 */
.box {
position: relative;
width: 350px;
height: 100%;
}
/* 方向文字、经纬度 */
.box .text {
position: absolute;
width: 350px;
height: 120px;
left: calc(50% - 175px);
top: 20px;
font-size: 13px;
font-weight: bold;
}
.box .text .direction-angle {
height: 50px;
line-height: 50px;
text-align: center;
font-size: 30px;
margin-bottom: 10px;
}
.box .text .latitude {
float: left;
margin-left: 50px;
color: rgba(0, 0, 0, .5)
}
.box .text .longitude {
float: right;
margin-right: 50px;
color: rgba(0, 0, 0, .5)
}
/* 指针 */
.box .point {
position: absolute;
height: 25px;
width: 2px;
left: 50%;
top: 165px;
background-color: black;
z-index: 10;
}
/* 表盘 */
.box .dial {
position: relative;
height: 300px;
width: 300px;
top: 170px;
left: calc(50% - 155px);
transform-origin: 158px 111px;
}
/* 外圈表盘刻度 */
.box .dial .scale {
position: absolute;
height: 300px;
width: 300px;
border-radius: 50%;
transform-origin: 150px 150px;
transform: translatez(0px) rotate(11deg);
}
/* 小刻度 */
.box .dial .scale ul li {
position: absolute;
left: calc(50% - 1px);
width: 2px;
height: 10px;
background-color: #ddd;
transform-origin: center 110px;
}
/* 中刻度 */
.box .dial .scale ul li:nth-of-type(5n) {
height: 12px;
}
/* 大刻度 */
.box .dial .scale ul li:nth-of-type(10n) {
height: 15px;
background-color: rgba(0, 0, 0, .5);
}
/* 数字和方向 */
.box .dial .num ul li,
.box .dial .num .direction {
position: absolute;
height: 25px;
width: 34px;
left: calc(50% - 10px);
top: 20px;
text-align: center;
line-height: 25px;
font-family: '宋体';
font-weight: 500;
font-size: 10px;
transform-origin: center 90px;
}
.box .dial .num .direction {
top: 55px;
transform-origin: center 55px;
}
/* 红色小标记 */
.dial .num .sign {
position: absolute;
left: calc(50% - 4px);
top: 30px;
border-top: 10px solid transparent;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid red;
}
.dial .num .direction span {
position: absolute;
display: block;
height: 100%;
width: 100%;
text-align: center;
transform-origin: center;
}
.north {
color: red;
}
.box .gradienter-in {
position: relative;
left: calc(50% - 10px);
top: -6%;
height: 30px;
width: 30px;
border-radius: 50%;
box-sizing: border-box;
transform-origin: center;
}
腾讯地图API组件
<iframe id="geoPage" width=0 height=0 frameborder=0 style="display:none" scrolling="no" src="https://apis.map.qq.com/tools/geolocation?key=你的秘钥&referer=myapp" frameborder="0">
javaScript部分
// 获取经纬度
// 这是腾讯地图API定义好的事件
// window.addEventListener("message", function(e) {
// var loc = e.data; 第一次获取到了保存好
var loc = {
module: 'geolocation',
nation: '中国',
province: '广东省',
city: '深圳市',
lat: '22.532332',
lng: '113.936553',
}
//将得到的经纬度转换后渲染到页面
oLatitudeSpan.innerHTML = parseInt(loc.lat) + '°' + parseInt((loc.lat - parseInt(loc.lat)) * 60) + "′" + parseInt(((loc.lat - parseInt(loc.lat)) * 60 - parseInt((loc.lat - parseInt(loc.lat)) * 60)) * 60) + "″";
oLongitudeSpan.innerHTML = parseInt(loc.lng) + '°' + parseInt((loc.lng - parseInt(loc.lng)) * 60) + "′" + parseInt(((loc.lng - parseInt(loc.lng)) * 60 - parseInt((loc.lng - parseInt(loc.lng)) * 60)) * 60) + "″";
//},false)
封装一个让元素绕着表盘中心旋转的函数
// 让元素围成一圈
function rotateDom(domArr, deg) {
Array.prototype.slice.call(domArr, 0).forEach(function (ele, index) {
ele.style.transform = 'translatez(0px) rotate(' + deg * index + 'deg)';
})
}
绑定获取设备方位信息事件
window.addEventListener("deviceorientation", function (e) {
if (e.alpha) {
// 初始化表盘
rotateDom(oScaleLiArr, 2)
rotateDom(oNumLiArr, 20)
rotateDom(oDirectionLiArr, 90)
// 指北针
oDial.style.transform = "translatez(0px) rotate(" + Math.round(e.alpha) + "deg)";
var str = '';
var dic = (Math.round((e.alpha) / 45) + 8) % 8;
switch (dic) {
case 0:
str = "北 ";
break;
case 1:
str = "西北 ";
break;
case 2:
str = "西 ";
break;
case 3:
str = "西南 ";
break;
case 4:
str = "南 ";
break;
case 5:
str = "东南 ";
break;
case 6:
str = "东 ";
break;
case 7:
str = "东北 ";
break;
};
// 方向角度
oDirecrionAngle.innerHTML = str + Math.abs(Math.round(360 - e.alpha)) + '°';
// 第一页的水平仪和方位文字归正
oGradienterIn.style.transform = 'translate3D(0px, 0px, 0px) rotate(' + -Math.round(e.alpha) + 'deg)';
oNorthSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha) + 'deg)';
oEastSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha + 90) + 'deg)';
oSouthSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha + 180) + 'deg)';
oWesternSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha - 90) + 'deg)';
// 水平仪 必须这么写,否则不识别,注意每个值都要空格隔开 (得出的角度较大,为了美观除以一个数)
oGradienterOutSpan.style.cssText = "box-shadow: rgb(136, 135, 135) " + -Math.round(e.gamma) / 2 + "px " + -Math.round(e.beta) / 2 + "px 0px 0px, rgb(0, 0, 0) " + -Math.round(e.gamma) / 2 + "px " + -Math.round(e.beta) / 2 + "px 0px 0px inset;";
oGradienterIn.style.cssText = "box-shadow: rgb(136, 135, 135) " + -Math.round(e.gamma) / 5 + "px " + -Math.round(e.beta) / 5 + "px 0px 0px, rgb(0, 0, 0) " + -Math.round(e.gamma) / 5 + "px " + -Math.round(e.beta) / 5 + "px 0px 0px inset;";
// 指针指到正北时,指针变红;
if ((e.alpha) % 360 < 1 || (e.alpha) % 360 > 359) {
oPoint.style.backgroundColor = "#f00";
} else {
oPoint.style.backgroundColor = "#000"
}
// 第二页
// 设备哪个轴偏转量大就让圆圈里显示谁的值
if (e.beta > e.gamma) {
oGradienterOutSpan.style.transform = 'translate3D(0px, 0px, 0px) rotate(' - Math.round(e.beta) + 'deg)'
oGradienterOutDiv.innerHTML = Math.abs(Math.round(e.beta)) + '°';
} else {
oGradienterOutDiv.innerHTML = Math.abs(Math.round(e.gamma)) + '°';
}
} else {
alert("您的设备不支持Deviceorientation功能,请用Android设备打开!")
}
}, false)
关于指南针判断方位部分画了张图便于理解
以上,写的还是有些匆忙,切页的功能实现的还没有扩大宽度来的美观一点,老是一卡一卡的,还有就是第二屏的角度会随着重力的方向排布。
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0px;
margin: 0px;
list-style: none;
}
:root,
body {
height: 100%;
}
body {
height: 100%;
display: flex;
justify-content: center;
}
.show {
height: 95%;
width: 350px;
transform: translate3D(0px, 20px, 0px);
}
.wrapper {
position: relative;
width: 700px;
height: 100%;
display: flex;
}
/* 第二页水平仪 */
.wrapper .gradienter-out {
position: relative;
height: 100%;
width: 350px;
}
.wrapper .gradienter-out span {
position: absolute;
left: calc(50% - 50px);
top: calc(50% - 50px);
height: 100px;
width: 100px;
border-radius: 50%;
}
.wrapper .gradienter-out span div {
position: absolute;
height: 50px;
width: 100px;
top: calc(50% - 25px);
text-align: center;
line-height: 50px;
font-size: 30px;
font-weight: bold;
transform-origin: center center;
}
/* 第一页 */
.box {
position: relative;
width: 350px;
height: 100%;
}
/* 方向文字、经纬度 */
.box .text {
position: absolute;
width: 350px;
height: 120px;
left: calc(50% - 175px);
top: 20px;
font-size: 13px;
font-weight: bold;
}
.box .text .direction-angle {
height: 50px;
line-height: 50px;
text-align: center;
font-size: 30px;
margin-bottom: 10px;
}
.box .text .latitude {
float: left;
margin-left: 50px;
color: rgba(0, 0, 0, .5)
}
.box .text .longitude {
float: right;
margin-right: 50px;
color: rgba(0, 0, 0, .5)
}
/* 指针 */
.box .point {
position: absolute;
height: 25px;
width: 2px;
left: 50%;
top: 165px;
background-color: black;
z-index: 10;
}
/* 表盘 */
.box .dial {
position: relative;
height: 300px;
width: 300px;
top: 170px;
left: calc(50% - 155px);
transform-origin: 158px 111px;
}
/* 外圈表盘刻度 */
.box .dial .scale {
position: absolute;
height: 300px;
width: 300px;
border-radius: 50%;
transform-origin: 150px 150px;
transform: translatez(0px) rotate(11deg);
}
/* 小刻度 */
.box .dial .scale ul li {
position: absolute;
left: calc(50% - 1px);
width: 2px;
height: 10px;
background-color: #ddd;
transform-origin: center 110px;
}
/* 中刻度 */
.box .dial .scale ul li:nth-of-type(5n) {
height: 12px;
}
/* 大刻度 */
.box .dial .scale ul li:nth-of-type(10n) {
height: 15px;
background-color: rgba(0, 0, 0, .5);
}
/* 数字和方向 */
.box .dial .num ul li,
.box .dial .num .direction {
position: absolute;
height: 25px;
width: 34px;
left: calc(50% - 10px);
top: 20px;
text-align: center;
line-height: 25px;
font-family: '宋体';
font-weight: 500;
font-size: 10px;
transform-origin: center 90px;
}
.box .dial .num .direction {
top: 55px;
transform-origin: center 55px;
}
/* 红色小标记 */
.dial .num .sign {
position: absolute;
left: calc(50% - 4px);
top: 30px;
border-top: 10px solid transparent;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid red;
}
.dial .num .direction span {
position: absolute;
display: block;
height: 100%;
width: 100%;
text-align: center;
transform-origin: center;
}
.north {
color: red;
}
.box .gradienter-in {
position: relative;
left: calc(50% - 10px);
top: -6%;
height: 30px;
width: 30px;
border-radius: 50%;
box-sizing: border-box;
transform-origin: center;
}
</style>
</head>
<body>
<div class="show">
<div class="wrapper">
<div class="box">
<div class="text">
<div class="direction-angle">西北 123°</div>
<div class="latitude">北纬 <span>123°5'23"</span></div>
<div class="longitude">东经 <span> 123°5'23"</span></div>
</div>
<!-- 指针 -->
<div class="point"></div>
<!-- 表盘 -->
<div class="dial">
<!-- 刻度 -->
<div class="scale">
<ul>
<li>*180
</ul>
</div>
<!-- 数字 -->
<div class="num">
<ul>
<li>0</li>
<li>20</li>
<li>40</li>
<li>60</li>
<li>80</li>
<li>100</li>
<li>120</li>
<li>140</li>
<li>160</li>
<li>180</li>
<li>200</li>
<li>220</li>
<li>240</li>
<li>260</li>
<li>280</li>
<li>300</li>
<li>320</li>
<li>340</li>
</ul>
<div class="sign"></div>
<div class=" direction north"><span>北</span></div>
<div class=" direction east"><span>东</span></div>
<div class=" direction south"><span>南</span></div>
<div class=" direction western"><span>西</span></div>
</div>
</div>
<!-- 中心水平仪 -->
<div class="gradienter-in"></div>
</div>
<!-- 第二页水平仪 -->
<div class="gradienter-out">
<span>
<div>12°</div>
</span>
</div>
</div>
</div>
<!-- <iframe id="geoPage" width=0 height=0 frameborder=0 style="display:none" scrolling="no" src="https://apis.map.qq.com/tools/geolocation?key=TMBBZ-5GYCP-AFQDK-L2QCS-K3323-HFBAX&referer=myapp" frameborder="0"></iframe> -->
<script>
var oScaleLiArr = document.getElementsByClassName('scale')[0].getElementsByTagName('li');
var oNumLiArr = document.getElementsByClassName('num')[0].getElementsByTagName('li');
var oDirectionLiArr = document.getElementsByClassName('direction');
var oLatitudeSpan = document.getElementsByClassName('latitude')[0].getElementsByTagName('span')[0]
var oLongitudeSpan = document.getElementsByClassName('longitude')[0].getElementsByTagName('span')[0];
var oGradienterOutSpan = document.getElementsByClassName('gradienter-out')[0].getElementsByTagName('span')[0];
var oGradienterOutDiv = document.getElementsByClassName('gradienter-out')[0].getElementsByTagName('div')[0];
var oGradienterIn = document.getElementsByClassName('gradienter-in')[0];
var oDial = document.getElementsByClassName('dial')[0];
var oPoint = document.getElementsByClassName('point')[0];
var oNorthSpan = document.getElementsByClassName('north')[0].getElementsByTagName('span')[0];
var oEastSpan = document.getElementsByClassName('east')[0].getElementsByTagName('span')[0];
var oSouthSpan = document.getElementsByClassName('south')[0].getElementsByTagName('span')[0];
var oWesternSpan = document.getElementsByClassName('western')[0].getElementsByTagName('span')[0];
var oDirecrionAngle = document.getElementsByClassName('direction-angle')[0];
// 让元素围成一圈
function rotateDom(domArr, deg) {
Array.prototype.slice.call(domArr, 0).forEach(function (ele, index) {
ele.style.transform = 'translatez(0px) rotate(' + deg * index + 'deg)';
})
}
// 获取经纬度
// 这是腾讯地图API定义好的事件
// window.addEventListener("message", function(e) {
// var loc = e.data; 瞎写的定位
var loc = {
module: 'geolocation',
nation: '中国',
province: '广东省',
city: '深圳市',
lat: '22.532332',
lng: '113.936553',
}
oLatitudeSpan.innerHTML = parseInt(loc.lat) + '°' + parseInt((loc.lat - parseInt(loc.lat)) * 60) + "′" + parseInt(((loc.lat - parseInt(loc.lat)) * 60 - parseInt((loc.lat - parseInt(loc.lat)) * 60)) * 60) + "″";
oLongitudeSpan.innerHTML = parseInt(loc.lng) + '°' + parseInt((loc.lng - parseInt(loc.lng)) * 60) + "′" + parseInt(((loc.lng - parseInt(loc.lng)) * 60 - parseInt((loc.lng - parseInt(loc.lng)) * 60)) * 60) + "″";
// }, false);
// 绑定获取设备方位信息事件
window.addEventListener("deviceorientation", function (e) {
if (e.alpha) {
// 初始化表盘
rotateDom(oScaleLiArr, 2)
rotateDom(oNumLiArr, 20)
rotateDom(oDirectionLiArr, 90)
// 指北针
oDial.style.transform = "translatez(0px) rotate(" + Math.round(e.alpha) + "deg)";
var str = '';
// 判断方位
var dic = (Math.round((e.alpha) / 45) + 8) % 8;
switch (dic) {
case 0:
str = "北 ";
break;
case 1:
str = "西北 ";
break;
case 2:
str = "西 ";
break;
case 3:
str = "西南 ";
break;
case 4:
str = "南 ";
break;
case 5:
str = "东南 ";
break;
case 6:
str = "东 ";
break;
case 7:
str = "东北 ";
break;
};
// 方向角度
oDirecrionAngle.innerHTML = str + Math.abs(Math.round(360 - e.alpha)) + '°';
// 第一页的水平仪和方位文字归正
oGradienterIn.style.transform = 'translate3D(0px, 0px, 0px) rotate(' + -Math.round(e.alpha) + 'deg)';
oNorthSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha) + 'deg)';
oEastSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha + 90) + 'deg)';
oSouthSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha + 180) + 'deg)';
oWesternSpan.style.transform = 'translatez(0px) rotate(' + -Math.round(e.alpha - 90) + 'deg)';
// 水平仪 必须这么写,否则不识别,注意每个值都要空格隔开 (得出的角度较大,为了美观除以一个数)
oGradienterOutSpan.style.cssText = "box-shadow: rgb(136, 135, 135) " + -Math.round(e.gamma) / 2 + "px " + -Math.round(e.beta) / 2 + "px 0px 0px, rgb(0, 0, 0) " + -Math.round(e.gamma) / 2 + "px " + -Math.round(e.beta) / 2 + "px 0px 0px inset;";
oGradienterIn.style.cssText = "box-shadow: rgb(136, 135, 135) " + -Math.round(e.gamma) / 5 + "px " + -Math.round(e.beta) / 5 + "px 0px 0px, rgb(0, 0, 0) " + -Math.round(e.gamma) / 5 + "px " + -Math.round(e.beta) / 5 + "px 0px 0px inset;";
// 指针指到正北时,指针变红;
if ((e.alpha) % 360 < 1 || (e.alpha) % 360 > 359) {
oPoint.style.backgroundColor = "#f00";
} else {
oPoint.style.backgroundColor = "#000"
}
// 第二页
// 设备哪个轴偏转量大就让圆圈里显示谁的值
if (e.beta > e.gamma) {
oGradienterOutSpan.style.transform = 'translate3D(0px, 0px, 0px) rotate(' - Math.round(e.beta) + 'deg)'
oGradienterOutDiv.innerHTML = Math.abs(Math.round(e.beta)) + '°';
} else {
oGradienterOutDiv.innerHTML = Math.abs(Math.round(e.gamma)) + '°';
}
} else {
alert("您的设备不支持Deviceorientation功能,请用Android设备打开!")
}
}, false)
</script>
</body>
</html>