关于定位的一些参考

整  理:朱 兵
时  间:2016-02-05
说  明: 定位的相关知识

摘要:关于定位,分为GPS定位和网络定位2种。GPS定位,精度较高,可达到10米,但室内不可用,且超级费电。网络定位,分为wifi定位和基站定位,都是通过获取wifi或者基站信息,然后查询对应的wifi或者基站位置数据库,得到的定位地点。定位数据库可以不断完善不断补充,所以,越定位越准确。

一、常见的定位:

GPS全球定位。

常见的GPS定位的原理可以简单这样理解:由24颗工作卫星组成,使得在全球任何地方、任何时间都可观测到4颗以上的卫星, 测量出已知位置的卫星到用户接收机之间的距离,然后综合多颗卫星的数据就可知道接收机的具体位置。

在露天环境下效果较好,获取位置信息非常精确。适合移动设备。 

缺点:在地铁等位置效果较差

IP地址定位。

适用于接入互联网的设备,通过浏览器是将位置信息发送给 ISP 服务商来解析,其IP 地址与服务商所在位置有关,可能与用户所在位置不同,所以这种方式的解析容易出现偏差。 

另外,由于国内大部分的省都是以省级为单位划分基站对外访问 IP ,也就是说,同样一个出口 IP,后面的对应用户
可能是跨多个城市的。也有一部分省是按照市一级为单位划分的,但是位置偏远。
备注:IP定位很方便,但是数据不准,需要及时更新,有很多商业化的服务。

WiFi定位。

设备只要侦听一下附近都有哪些热点,检测一下每个热点的信号强弱,然后把这些信息发送给网络上的服务端。服务器根据这些信息,查询每个热点在数据库里记录的坐标,然后进行运算,就能知道客户端的具体位置了。一次成功的定位需要两个先决条件:客户端能上网 ,侦听到的热点的坐标在数据库里有。

优点:这种方式与GPS效果同样精确,适用于室内环境的移动设备。

缺点:

  • 你的这个wifi信号,如果在数据库中没有被记录在案,那就没法定位了。比如,如果你买了个新的无线路由器,靠它肯定是没法帮助你的移动设备定位的。
  • 数据更新有延迟,WIFI覆盖并不大,局限
    原理说明:当你的移动设备需要使用wifi定位的时候,它会搜索周围的wifi信号,同时在数据库中搜索,得到地理位置的数据,加上定位提供商收集的海量数据,能够构建出信号的“指纹”,比基站定位更精准。

④基站定位

我们把手机基站的覆盖范围想像成一个个以基站为圆心的圆,需要定位时,手机就向周边多座基站发送测量信号,并计算这些测量信号到达基站所需要的时间,推算出手机距离基站的直线距离,再经过数学运算,手机位置坐标就可由3个基站圆的交点来确定。

优点:LBS定位的优势是方便、成本低,因为它是通过手机进行定位的。理论上说,只要计算三个基站的信号差异,就可以判断出手机所在的位置,而且用户所持终端只需一部手机即可。因此,只要用户手机有信号,就可以随时进行位置定位,而不受天气、高楼、位置等影响。

缺点:定位精度随所处位置基站数不同会有变化。

百度地图等在web开发时并不提供相关api

二、测试结果:

初步得到的结果:GPS>WiFi/基站>IP

1、GPS和WIFI相对测试的结果较好。
2、局限性:WIFI效果较好,但是局限性很大。基站定位在web开发时比较麻烦
3、目前比较好的方式,就是读取GPS的相关信息(比如经纬度等等),再做进一步操作。
4、在精准度要求比较高的情况下,并不推荐使用ip定位。ip定位好处是:并不需要用户授权,方便。

三、业务说明:

以百度地图为例

1、APP开发的话
百度定位sdk,综合了wifi定位、基站定位

2、web开发的话

浏览器定位

浏览器定位插件,封装了标准HTML5定位,并且包含纠偏模块。

html5定位:拿到的是GPS的数据,定位准确

备注:获取经纬度数据,想获得地址,需要纠偏,再使用接口获得。

鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的。

Internet Explorer 9、Firefox、Chrome、Safari 以及 Opera 支持地理定位。

注释:对于拥有 GPS 的设备,比如 iPhone,地理定位更加精确。

更多可参考geekman的文章:http://blog.geekman.vip/archives/446

另外,浏览器定位插件也是混合定位,获取了wifi、基站信息用以定位,对于拥有 GPS 的设备,比如 iPhone,由于获得GPS信息,使得地理定位更加精确。

★浏览器定位,最好使用在手机浏览器上,会更加准确,也更加符合使用场景。PC浏览器上,建议使用IP定位。

通过网络获取IP信息,然后查询IP数据库,获取相应的地址信息。

IP数据库也是可以完善补充,越来越丰富的,所以也是越使用越准确的。

但如果IP有跳转,有篡改等,那么IP定位就会不准确了。

demo:http://developer.baidu.com/map/jsdemo.htm#i8_2

③web接口
嫌开发不方便,可以直接调用web接口,体验更快,缺点是次数限制。
育儿网对一些接口进行了封装(100w次)
根据ip获取地理位置
根据经纬度获取地理位置(百度接口)

具体api地址在:http://api.xinfotek.com/apidoc/doc/

关于JSAPI/webAPI的小小说明

1、js是浏览器端,而web是服务端。

2、在使用上Web更简单,若只想使用服务,直接通过调用接口获取结果的话,并且需求量并不大的 时候,建议使用web。(百度js调用次数不限)

3、想展示地图,或者超过接口限制,比较复杂的web开发,想要的功能并没有提供相应的接口,会需要用到js。

Tip:使用之前需要申请秘钥.

秘钥分为浏览器端,服务端,

为了安全性可设置白名单:
浏览器端是设置域名:如*.ci123.com,只能在该域名下访问

服务端是设置ip白名单,不限制的话 0.0.0.0/0
3、在微信中使用

引用微信js即可使用

给的接口只有两类,一类是用内置浏览器(使用并不多),一类是得到想要的配置

示例一:使用微信内置地图查看位置接口
wx.openLocation({
latitude: 0, // 纬度,浮点数,范围为90 ~ -90
longitude: 0, // 经度,浮点数,范围为180 ~ -180。
name: '', // 位置名
address: '', // 地址详情说明
scale: 1, // 地图缩放级别,整形值,范围从1~28。默认为最大
infoUrl: '' // 在查看位置界面底部显示的超链接,可点击跳转

});
示例二:获取地理位置接口
wx.getLocation({
    type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
    success: function (res) {
        var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
        var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
        var speed = res.speed; // 速度,以米/每秒计
        var accuracy = res.accuracy; // 位置精度
    }
});
 
四、其他说明
①特殊说明:
1、通过百度jsapi测试结果看,通过ip定位城市效果也会存在比较大的误差,更别提精确定位。
但是只要数据库足够丰富,定位结果会准确的多,但是成本会特别高。
2、对于GPS坐标转换成使用百度api需要转换百度坐标(纠偏)
②自己写的参考demo
1、js版(利用html5定位,再调用百度api,调用次数不限)
好处:去除了地图展示等一些功能,直接显示位置。
演示效果
QQ图片20160205154740
2、web请求,这个比较简单,直接根据经纬度调用接口。
好处:少一次调用
③参考资料/网站:
3、百度开发平台:http://lbsyun.baidu.com/

 

 

【前端技术文档】gulp spriter 插件使用

整    理:肖雅君

时    间:2016-02-05

说    明:gulp-css-spriter 将css代码中的切片图片合并成雪碧图

一、下载安装gulp

1.1 下载安装node.js

1.2 命令行测试是否安装成功

1.3 定位到项目

1.4 安装gulp

二、开始使用gulp

2.1 新建gulpfile.js文件

三、gulp-css-spriter

3.1 gulp-css-spriter使用步骤

3.2  使用技巧

一、下载安装gulp

1.1 下载安装node.js

下载链接:https://nodejs.org/en/   下载后直接安装即可。

1.2 命令行测试是否安装成功

Cmd

输入命令:Node –v  看是否返回node版本号,若是返回则安装成功。

输入命令:npm –v  同上是否返回npm的版本号

如下图:则是安装成功。

1

Ps: NPM是基于命令行的node包管理工具,它可以将node的程序模块安装到项目中,在它的官网https://npmjs.org/ 中可以查看和搜索所有可用的程序模块。

1.3 定位到项目

直接输入d:  按回车键,进入d盘,再进入到安装文件夹,如下图:

2

1.4 安装gulp

遇到的问题:

参考资料中有sudo npm install –g glup安装命令,但是是出错的。

3

Sudo是以管理员身份执行命令,是切换到最高用户权限,su是切换用户,这是linux里才有的,windows是没有的。

将sudo去掉,用npm install -g gulp安装也是不行的。

4

使用npm install --global gulp是可以安装的,但是有一个warn警告。

5

查看版本号也是能查看到的:

6

二、开始使用gulp

2.1 新建gulpfile.js文件

建立gulpfile.js文件,作为它的主文件,放入到自己的项目目录中。

然后在gulpfile.js中定义自己的任务。

 

三、gulp-css-spriter

功能:将css代码中的切片图片合并成雪碧图

3.1 gulp-css-spriter使用步骤

(1)安装gulp-css-spriter

输入命令npm install gulp-css-spriter

7

安装成功后自己建的文件里会产生node_modules文件夹,里面会有一个刚安装的gulp-css-spriter文件夹。

89

(2)配置gulpfile.js文件

var gulp = require('gulp'),

spriter = require('gulp-css-spriter');

 

gulp.task('css', function(){

var timestamp = +new Date();

//需要自动合并雪碧图的样式文件

return gulp.src('styles/style.css')//雪碧图的原路径文件

.pipe(spriter({

// 生成的spriter的位置

'spriteSheet': 'combine/images/sprite'+timestamp+'.png',

// 生成样式文件图片引用地址的路径

// 如下将生产:background:url(images/sprite20160205.png)

'pathToSpriteSheetFromCSS': 'images/sprite'+timestamp+'.png'

}))

//产出路径

.pipe(gulp.dest('combine'));

});    //产出路径

2

(3)执行编译输入命令:gulp css

55

(4)编译前后文件目录截图对比

a.编译之前:

合并前文件目录:

11

合并前style.css样式:

22

合并前图片文件夹:

44

b.编译之后:

合并后文件目录:

66

combine文件夹里的文件:

77

combine里的style.css:

88

combine里的图片文件夹:

99

(5)可能出现的问题:

在编辑后可能会出现如下问题:

11

Cannot find module ‘gulp-minify-css’;

需要再次安装gulp-minify-css。执行命令:npm install gulp-minify-css

12

安装完毕后再次编译:(点击可查看动图编译过程)

15

 3.2  使用技巧

gulp-css-spriter默认会对样式文件里,所有的background/background-image的图片合并,但实际项目中,我们不是所有的图片都需要合并。

background-image: url(../images/data3.png?__spriter);//有?__spriter后缀的合并

background-image: url(../images/part-bg.png); //不合并

修改下面文件可以按需合并:

node_modules\gulp-css-spriter\lib\map-over-styles-and-transform-background-image-declarations.js

13

48行开始的if-else if代码块中,替换为下面代码

位置:

14

// background-image always has a url 且判断url是否有?__spriter后缀

if(transformedDeclaration.property === 'background-image' && /\?__spriter/i.test(transformedDeclaration.value)) {
transformedDeclaration.value = transformedDeclaration.value.replace('?__spriter','');
return cb(transformedDeclaration, declarationIndex, declarations);}
// Background is a shorthand property so make sure `url()` is in there 且判断url是否有?__spriter后缀
else if(transformedDeclaration.property === 'background' && /\?__spriter/i.test(transformedDeclaration.value)) {
transformedDeclaration.value = transformedDeclaration.value.replace('?__spriter','');
var hasImageValue = spriterUtil.backgroundURLRegex.test(transformedDeclaration.value);
if(hasImageValue) {
return cb(transformedDeclaration, declarationIndex, declarations);}
}

 

再次执行即可。

 

参考链接:

https://github.com/laoshu133/gulp-css-spritesmith

https://github.com/aslansky/css-sprite

 

【前端技术文档】PS快速切图方法

整    理:贾会迎、晋哲

时    间:2016-02-05

说    明:PS处理同类型不同尺寸图标的快捷方法

问题:当同一版块中的每个图标的宽高各异时,在切图时需要为这些图标设置一个统一的宽高,方便样式统一编写。如何快速准确的确定切图尺寸,同时分成两套不同状态样式?

例如以下按钮的图标:
p-1

操作步骤
一、同时选择几个图标的图层
p-2

二、复制图层—新建—裁切(透明像素部分)。得到如下图
p-3

三、统一颜色样式(将绿色图标改为灰色)
1、提取颜色值,可保存至背景色
p-4
2、在图层空白处双击,调出“图层样式”面板,设置“颜色叠加”
p-5
3、图标颜色改变为灰色(效果)
p-6

四、将图标水平垂直居中,多个图标重叠显示,来确定图标的准确尺寸。
p-7

五、确定图标大小,逐一显示并保存
1、裁切透明像素,获得图标的准确大小
p-8
2、查看此时“图像--画布”大小,根据图标实际需要设置最大宽高值,最好设置为偶数,以方便样式设置。如下图,高度可以设42px、46px、50px等等
p-9

p-10
3、按设计图顺序逐一显示图层并保存

六、设置第二套状态样式(如图绿色)。
1、提取交互图标的颜色,可保存在前景色中
p-11
2、在图层空白处双击,调出“图层样式”面板
p-12

p-13
3、选择打开“颜色叠加”面板,设置叠加的颜色
p-14
4、在图层区域右击,选择“拷贝图层样式”
p-15
5、选中其他图层,右击选择“粘贴图层样式”,后逐一显示并保存图片。
p-16

p-17

p-18

七、保存的图标文件效果,注意按照设计图顺序和统一的规则命名
p-19

HHuploadify(基于Huploadify)的文件上传插件

整  理:雷  媛
时  间:2016-02-05
说  明: 上传图片的插件

一、简介

基于Huploadify(基于uploadify)的图片上传插件,自动上传,上传进度条,上传后预览

 二、安装

获取代码:下载HHuploadify的源代码。

网页中引入jquery和css

<script src="jquery-2.2.0.min.js"></script>
<script src="jquery.HHuploadify.js"></script>
<link rel="stylesheet" href="HHuploadify.css"> 
备注:可以在HHuploadify.css中对HHuploadify的样式进行修改。

三、使用方法:

 3.1  上传多张(一组)图片

demo:
<div id="upload"></div>
<script>
 $('#upload').HHuploadify({
        fileTypeExts:'*.jpg;*.png;*.gift',//允许上传的文件类型
        uploader:'sub/upload_sub.php' // 必须的,必须指定用来处理上传逻辑的后端处理URL
    });
</script>
点击按钮之后可以多选多张图片,每张图片会各自提交到upload_sub.php。这里提示一下,uploadify本身就是一张一张图片提交的,而不是所有图片一起提交。upload_sub .php可以是你自己的URL,在这个URL进行图片处理和保存,并且返回一个包含url字段的json字符串,通过这个url字段让上传区域展示图片。

3.2  单张图片上传

在上面的代码中,只需要加入一个isSingle参数即可:
demo:
<div id="upload"></div>
<script>
    $('#upload').HHuploadify({
        fileTypeExts:'*.jpg;*.png;*.gift',
        isSingle:true,
        uploader:'sub/upload_sub.php '// 必须的,必须指定用来处理上传逻辑的后端处理URL
    });
</script>
多张图片上传的时候,无论你上传了多少张图片,末尾都会存在选择图片的按钮,你还可以继续上传。而单张图片上传时,选择图片时只能选择一张,选择好之后就进入上传状态,按钮消失,不能继续选择图片进行上传。

四、初始化参数
js中默认的参数如下所示:
fileTypeExts:'*.*',//允许上传的文件类型,格式'*.jpg;*.doc'
uploader:'',//文件提交的地址
auto:true,//是否开启自动上传
method:'post',//发送请求的方式,get或post
multi:true,//是否允许选择多个文件
isSingle:false,// 是否是单个文件上传,如果是单个文件上传,选择文件后,上传按钮会消失,multi也会被强制设定为false
formData:null,//发送给服务端的参数,格式:{key1:value1,key2:value2}
fileObjName:'file',//在后端接受文件的参数名称,如PHP中的$_FILES['file']
fileSizeLimit:2048,//允许上传的文件大小,单位KB
showUploadedFilename:false,//是否显示上传文件名
showUploadedPercent:false,//是否实时显示上传的百分比,如20%
showUploadedSize:false,//是否实时显示已上传的文件大小,如1M/2M
buttonText:'选择文件',//上传按钮上的文字
itemTitle:false,// 该上传item区域的标题:该值将作为上传按钮的提示语,上传时,会显示在左上角,注意,每一个上传区都会有,所以尽可能再isSingle=true的情况下使用
removeTimeout: 1000,//上传完成后进度条的消失时间,单位毫秒
itemTemplate:itemTemp,//上传队列显示的模板
onUploadStart:null,//上传开始时的动作
onUploadSuccess:null,//上传成功的动作
onUploadComplete:null,//上传完成的动作
onUploadError:null, //上传失败的动作
onInit:null,//初始化时的动作
onCancel:null,//删除掉某个文件后的回调函数,可传入参数file
onClearQueue:null,//清空上传队列后的回调函数,在调用cancel并传入参数*时触发
onDestroy:null,//在调用destroy方法时触发
onSelect:null,//选择文件后的回调函数,可传入参数file
onQueueComplete:null//队列中的所有文件上传完成后触发
若是想要更改初始化参数,可在jquery.HHuploadify.js中修改,也可以在上述demo中的js中引用HHuploadify的时候修改,例如:
<script>
 $('#upload').HHuploadify({
     auto:true,
     fileTypeExts:'*.jpg;*.png;*.gift;*.doc',//允许上传的文件类型 
     isSingle : true,//上传一张图片图片
     fileSizeLimit:300,//图片最大300KB
     showUploadedSize:true,//实时显示已上传的文件大小,如1M/2M
     method:'post',//发送请求的方式,get或post
     formData: {item_id: <?php echo $item_id;?>},//传递到sub端的参数 
     uploader:'sub/upload_sub.php',
     onUploadComplete:function(file,data) {
         alert('图片上传成功'),
    }

});
</script>

继续阅读HHuploadify(基于Huploadify)的文件上传插件

前端半年水平

一、移动端
移动端dpr适配知识点
移动端性能优化

二、项目流程
团队协作完成流程页面能力
独立完成小型项目能力

三、CSS预处理器
Sass(项目实现统一使用Sass编写样式)
postCSS

四、前端标准/规范
ECMAScript3/5
ECMAScript6

五、编程语言
JavaScript
Node.js

六、包管理器 npm

七、JS框架
Angular
React

八、前端项目构建工具
gulp
grunt
FIS

九、代码组织(模块化)
类库模块化 CommonJS/webpack
业务逻辑模块化 bower
文件加载 Require
模块化预处理器 Browserify

十、软技能
知识管理/总结分享
沟通技巧/团队协作
需求管理/项目管理
交互设计/可用性/可访问性知识

前端半年水平树

关于ip的那些事


编	写:袁	亮
时	间:2014-05-20
说	明:关于ip的那些事

一、ip传递过程
	1、【真实客户端】 ==> [多级代理服务器] ==> [CDN加速] ==> [前端代理nginx|squid] ==> 【apache】==> 【PHP】
	2、中文括号的是必然会经过的,英文括号是可能经过的
	3、标准的ip传递是REMOTE_ADDR和HTTP_X_FORWARDED_FOR,前一个跟当前服务连接的真实ip,后一个是请求到前一个ip之前,经过了哪些代理
	4、REMOTE_ADDR是不可伪造的,HTTP_X_FORWARDED_FOR是可以任意修改的
	5、按标准,每传递到下一层,都会将上一层的实际ip地址加入到HTTP_X_FORWARDED_FOR中,继续传递
	6、对每一层来说,只有上一层的时间地址是可信的(REMOTE_ADDR),HTTP_X_FORWARDED_FOR均有风险
	7、真实情况中,到了cdn或者前端代理之后,ip传递都是可信的(我们自己可控制),之前的都有篡改的危险

二、各服务的真实ip传递情况
	1、CDN 快网的cdn会将用户的实际地址或者代理服务器地址传递到后面的服务中
		$_SERVER["HTTP_USER_IP"]	【不用快网的时候可伪造】
		$_SERVER["HTTP_FW_ADDR"]	【不用快网的时候可伪造】
		测试了一个新的cdn测试,没有传递真实ip过来

	2、nginx代理的情况下,可以使用x_real_ip来获取真实ip(有cdn的时候,该值获取的是cdn的ip地址)
		$_SERVER["HTTP_X_REAL_IP"]	【不用nginx的时候可伪造】

	3、$_SERVER["HTTP_CLIENT_IP"] :代理服务器发送的客户端真实ip【可伪造】

三、现在使用的获取ip函数
	a、如果有HTTP_CLIENT_IP,则该ip为用户ip(可被伪造)
	b、如果有HTTP_X_FORWARDED_FOR,则将HTTP_CLIENT_IP也加入到HTTP_X_FORWARDED_FOR,判断HTTP_X_FORWARDED_FOR中的ip是否是内网的,取第一个非内网的ip为客户端真实ip
	c、经过以上两步还没有取到ip的话,则根据REMOTE_ADDR取用户的ip
	ps:该函数的问题在于,前面两个的ip都是可以被任意伪造改写,从而导致获取不到用户的真实ip情况

四、附:(线上使用的获取ip函数)
function getIp(){//获取IP函数
        $ip = false;
        if(!empty($_SERVER["HTTP_CLIENT_IP"])){
                $ip = $_SERVER["HTTP_CLIENT_IP"];
        }
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
                if ($ip) {
                        array_unshift($ips, $ip);
                        $ip = FALSE;
                }
                for ($i = 0; $i < count($ips); $i++) {
                        if (!preg_match("/^(10|172\.16|192\.168)\./", $ips[$i])) { // 判断是否内网的IP
                                $ip = $ips[$i];
                                break;
                        }
                }
        }
        return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
}