Code Monkey home page Code Monkey logo

blog's Introduction

blog

这是我的个人博客,从今天开始,将整理一些以前记录的东西到这个上面来

也算是一种分享吧

gitHub已经兴起多年了,然而我在上面并无所作为,表示很遗憾

但是从今天开始,我将在此积累,希望gitHub不要被墙吧

我可能会涉及的内容包括:

  • JS

  • CSS

  • HTML5

  • GIS

  • WEBGL

  • PHP

  • PYTHON

  • GO

最新内容

WebAssembly让你的JS运行效率提高10倍

HTTP/2深入学习

leaflet源码解析

cursor你不知道的值

console.被我们遗忘的优秀调试工具

百度坐标、火星坐标、wgs84相互转换、wgs84到web墨卡托投影的转换

坐标系经纬度与三维中XYZ的转换

关于坐标系、投影与瓦片

前端地图瓦片的拼接

POSTGIS里的geometry 和geography,如何正确计算空间距离

有时间去看issues的啦!

联系我

微信:liu891599396

Mail:[email protected](基本不看)

微信公众号:开源GIS地图与信创

官网:http://www.newgis.top

因为专业所以人少。

blog's People

Contributors

liujiusheng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

关于js对象的潜复制与深度复制

众所周知;
js里面简单的值类型变量给变量赋值会直接复制,而对象类型变量给变量赋值则只是引用,并不会复制,改变一个变量的值另一个变量也会跟着改变。这在很大程度上造成了问题。

对于一维数组可以简单地使用 slice(0)来重新生成一个数组
对于二维数组则不能用这种方法只能用JSON.parse(JSON.stringify());这种方法量简单

但奇怪的是通过递归重新生成一个新二维数组似乎也不能解决这个浅复制的问题。

ArcGIS Server JavaScript Pinting Service实现地图打印功能

能实现什么?

地图打印、地图导出为图片

为了实现一个地图编辑、保存、修改、导出功能,我们需要将地图数据存储到服务端,然后在修改时通过后台接口取出已存的数据,最后绘制到地图中

环境要求

ArcGIS Server 10.1以上版本
ArcGIS JavaScript API(测试时使用的3.18版本,现在的链接是3.20)

1. 直接保存整个地图的方案不现实也行不通

操作过程中发现,并不能直接使用JSON.stringify()将地图的JSON对象转换成字符串向后端接口传递,原因是地图的JSON对象有自引用的情况,这种情况会导致JSON.stringify()方法出错,从而不能完成转换。

由于所有用户操作形成的要素都绘制在graphics图层中,所以提取地图中的graphics要素并存储起来就可以了。而graphics需要的信息也只用geometry和symbol两个属性需要存储。所以只需提取这两个属性并重新保存成新的对象通过 JSON.stringify()方法转换成字符串就可以存储了。

2. 部分属性存在于原型链中,需要手动验证提取

JavaScript基于原型链,ArcGIS JavaScript API 同样基于原型链,graphics的部分属性通过__proto__的方式存在,比如symbol的type属性,部分情况下在symbol对象下有此属性,部分情况下则存在于__proto__中,需要使用到hasOwnProperty()方法进行验证,以保证保存的数据的完整性。

3. 传入JSON对象实例化会出错

通过new TextSymbol(json)new SimpleMarkerSymbol(json)等方法直接传入后端取回的json对象实例化时会绘制不正确(界面上能正确显示,但是再交保存时就会出错,报toJSON() is undefined 错误)

正确的姿势为,提取已经保存的属性,new一个对象后一个一个地绑定属性,这种方法唯一的问题就是每个属性都要去手动处理太麻烦了,建议好好研究一下实例化时直接传入json对象的那个方法,有可能我用错了。

4. 打印时,你需要通过PrintTask()生成一个导出地图的实例,需要传入一个URL

URL示例:http://localhost:6080/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export Web Map Task

此链接可在:arcgis server管理界面->服务->utilities->PrintingTools->功能界面,找到。我想此界面的WPS和上传功能应该都要开启吧。

PrintingTools功能默认为关闭状态,需要手动启动

5. 听说后台运算量大时还需要配置异步,即设置async为true

over.

Vuex使用computed时的一个小细节

不要在模块内对computed属性进行赋值,会出现has no setter的奇怪错误。

究其原因大概在于所有state都通过vuex管理了,那么修改它就要通过commit方式提交mutations,
在模块内若改变其值会直接触发本模块的computed,而不是通过commit的方式全局刷新,所以会出问题。

天地图的调用

Angular+ui-router+ArcGIS JS API+懒加载复杂条件下webpack打包

我想要达到的效果:不用打包的情况下原来代码能跑起来,能打包并且打包了之后代码也能跑起来

ArcGIS JS API路径问题
项目中混合有require 和 define

WEBPACK_EXTERNAL_MODULE_8

在define()中导入模块时,默认会在后面添加.js,当导入html模板时.html文件后面也会被自动添加上.js,导致加载出错,所以,在不编译环境下导入模板时前面添加了text!,提示amd规范要使用文本类型导入不自动加上.js,但是这种方式在webpack编译时会出错。
现在项目中所有directive里面的代码模板html都有text!

HtmlWebpackPlugin插件可以有效解决.html文件没加text!时打包也自动添加.js的问题

关于懒加载,webpack官方明确说明:
官方推荐的方式为import()方法,
用得较多的还有require.ensure()方法。
webpack 在构建时,会静态解析(statically parse)代码中的 require.ensure()。在其中任何被引用的依赖模块,或在回调函数中被 require() 的模块,都将被分离到一个新的 chunk 中。这个新的 chunk 会被生成为异步的 bundle,由 webpack 通过 jsonp 来按需加载。

打包的时候有运行时的概念,一定要记住,遇到什么can not find module这一类的错误的时候一般都是因为模块是运行时加载的模块,而运行时的模块需要有实际的文件存在,若没有实际文件存在则会报错。比如我们这个里面关于app模块的错误

angular本身并不支持异步加载模块,所以使用了oclazyload先注入模块,然后加载,所以不会出错。

webpack提供的ensure和import()方法可以告诉webpack这个模块应该打成一个独立的包,跟lazyload没有什么实际的关联。

配置externals的时候有个空格,一定要注意。
The 'commonjs ' + request defines the type of module that needs to be externalized.

最终方案总结:
编写配置文件,修改入口文件为bootstrap.js文件
设置externals排除掉arcgis js api和angular等外部库,
设置libraryTarget为amd(小写,用于输出打包后的代码为amd规范,方便与DOJO和arcgis集成)
需要的loader暂时有:ng-annotate-loader,style-loader,css-loader,file-loader,raw-loader。
配置resolve.modules,将代码的主要文件夹地址放入数组中,以方便webpack在打包时查找文件(打包时路径一定要正确,webpack打包时路径运行时有点奇怪,所以一定要注意)
其它待续。。。

要打包指令的时候需要先在路由处require该指令的bootstrap文件,然后需要修改bootstrap文件中的angular依赖模块为当前路由模块

参考:代码分离 - 异步

参考:Lazy load AngularJS with Webpack

escape()、encodeURI()、encodeURIComponent()区别详解

  1. escape() 除了 ASCII 字母、数字和特定的符号外,对传进来的字符串全部进行转义编码,因此如果想对URL编码,最好不要使用此方法。

  2. encodeURI() 用于编码整个URI,因为URI中的合法字符都不会被编码转换。

  3. encodeURIComponent方法在编码单个URIComponent(指请求参数)应当是最常用的,它可以讲参数中的中文、特殊字符进行转义,而不会影响整个URL。

elasticsearch入门

查看所有index(索引):http://ip:端口/_cat/indices?v
查看所有type(表):http://ip:端口:/_mapping

根据字段统计某一类型数量,size不设置时超过的数据不会被统计,field是字段,也可以是_type

“size":0,
"aggs": {
            "group_yy": {
              "terms": {
                "field": "_type",
                "size":2000
              }
            }
          }

所有的聚合操作都放在aggs(aggregations)下,group_yy是自己定义的名字,用于在结果中显示。
最外层size设置为0时表示不返回查询详细结果,只返回统计信息。

在es header管理面板中,要注意指定index,注意使用POST方法,注意查询语句中只要body的内容,不要body这一级,最外层用{}包裹。

columns多列布局

浏览器已经更新了这么多版本了,多列布局这么好的特性我想也可以开始用了。

目前columns支持情况:
ie10+可直接用,firefox加-moz-前缀可用,chrome,safari,opera等和安卓ios平台均可加-webkit-前缀可用

使用:
columns支持复合属性设置,它是针对设置了这个属性的所有子元素进行分列。
一般情况下子元素为很多个p标签,整体是一篇文章的样式。
若为子元素设置了样式,则子元素的样式也会生效,但对于整个内容来说它还是一个分列布局。
比如我们设置了第一大段的width为2000px远远超过自动分列出来的每一列宽度,那么第一大段会以2000px的宽度去渲染它的内容以保证显示正确,但它并不会因此而将columns撑开从而所致某一列宽度比其它的大。
相当于它是画了一个死框,将一行分成多列,每一列的宽度根据设置已经固定死,不会因为内容而改变。
内容过宽会绘制到外面去,但不影响整体布局,列也不会将绘制出去的部分隐藏。

columns:每一列的宽度 || 列数
若设置列数则会自动分配宽度,若设置宽度则会自动分配列数将容器填满。
column-gap:设置或检索对象的列与列之间的间隙
column-rule:宽度 样式 颜色。设置或检索对象的列与列之间的边框
column-span:设置或检索对象元素是否横跨所有列(firefox 不支持)
column-fill:设置或检索对象所有列的高度是否统一(听说目前只有 firefox 支持没测试出过效果)
column-break-before:设置或检索对象之前是否断行
column-break-after:设置或检索对象之后是否断行
column-break-inside:设置或检索对象内部是否断行

CSS高级体验设计--鼠标指针样式

常用的鼠标指针样式(cursor的值)也就:
url:需使用的自定义光标的 URL。
(注释:请在此列表的末端始终定义一种普通的光标,以防没有由 URL 定义的可用光标。)
default: 默认光标(通常是一个箭头)
auto: 默认。浏览器设置的光标。
crosshair: 光标呈现为十字线。
pointer: 光标呈现为指示链接的指针(一只手)
move: 此光标指示某对象可被移动。
e-resize: 此光标指示矩形框的边缘可被向右(东)移动。
ne-resize: 此光标指示矩形框的边缘可被向上及向右移动(北/东)。
nw-resize: 此光标指示矩形框的边缘可被向上及向左移动(北/西)。
n-resize: 此光标指示矩形框的边缘可被向上(北)移动。
se-resize: 此光标指示矩形框的边缘可被向下及向右移动(南/东)。
sw-resize: 此光标指示矩形框的边缘可被向下及向左移动(南/西)。
s-resize: 此光标指示矩形框的边缘可被向下移动(南)。
w-resize: 此光标指示矩形框的边缘可被向左移动(西)。
text: 此光标指示文本。
wait: 此光标指示程序正忙(通常是一只表或沙漏)。
help: 此光标指示可用的帮助(通常是一个问号或一个气球)。

这几个,通过百度,w3school,大多数书籍查看到的也只有这几个属性,
其实还有:
none: 不显示光标(与url设置的图片为空白图片时效果一样)
context-menu: 暂无效果
cell: 像excel中鼠标悬浮在表格上一样
vertical-text: 文字竖排时的光标(与输入框的效果一致,只是方向不同)
alias: 键头上有个小键头
copy: 键头上有个小加号
no-drop: 禁止图标
not-allowed: 禁止图标
ew-resize: 左右双向键头
ns-resize: 上下双向键头
nesw-resize: 右上到左下双向键头
nwse-resize: 左上到右下双向键头
col-resize: 左右拖动分隔线效果
row-resize: 上下拖动分隔线效果
all-scroll: 与move一样
zoom-in: 放大图标
zoom-out: 缩小图标
这几个属性

地图中需要经常用到的有all-scrollzoom-inzoom-out

webgl(一) 顶点

顶点缓存的作用,不光是保存顶点的位置,位置以外跟顶点相关的信息都可以用顶点缓存来保存。

比如,顶点的法线,颜色,文理坐标等所有跟顶点相关的信息都可以用顶点缓存来保存和管理。但是需要注意一点的是,向顶点信息中追加信息的时候,需要使用相应的VBO(vertex buffer object)。

所以构建VBO的函数最终都会return生成的VBO。

VBO的生成过程中,首先在最初的时候必须把数据保存到数组中,因为顶点的信息(位置)中必须有x,y,z,所以数组的长度必须是顶点数x3,这个时候需要注意,数组不可以使用多维数组,VBO的生成需要使用一维数组。

注意:“顶点数”并不是指xyz。所以数组可以为两列三行。两列三行时一个点只由xy组成,z大概默认为0吧。所以每一行后面还可以跟许多其它参数。

关于JavaScript中的this

this一般指当前作用域

1. 构造函数

如果函数作为构造函数用,那么其中的this就代表它即将new出来的对象。

2. 函数作为对象的一个属性

如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时,函数中的this指向该对象。

3. 函数用call和apply调用

当一个函数被call和apply调用时,this的值就取传入的对象的值。

4. 全局调用普通函数

在全局环境下,this永远是window。

5.在AJAX异步函数中

AJAX中使用了xhr对象,没有使用this对象,原因是onreadystatechange事件处理程序的作用域问题。如果使用this对象,在有的浏览器中会导致函数执行失败,或者导致错误发生。因此,使用实际的XHR对象实例变量是较为可靠的一种方式。所以打印出this为undefined。

6.setInterval和setTimeout

间歇调用和超时调用的情况一样,回调函数也是在全局环境中执行的。

7.事件处理程序

与dom交互的时候不论函数是写在html里面还是addEventListener添加,this都指当前dom,有时还 需要target来获取当前dom否则获取的是父元素。(没详细验证过,懒得写)

使用python3实现学英文软件

在8082端口打开一个web服务器:python -m http.server --cgi 8082

wsgiref

python脚本必须用cgi模式运行
脚本必须放在cgi-bin和ht-bin文件夹中
其它文件夹下的文件被当做静态文件不做解析

关于websocket

代码全部在这里了
var ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};

ws.onclose = function(evt) {
console.log("Connection closed.");
};

websocket的前端开发非常简单,主要就是js的事件,onopen,send,onmessage,onclose和new WebSocket实例化,

主要在于后端的处理,

websocket连接需要先通过http请求返回一个upgrad,将请求升级为socket连接才行。
若不借助框架的话,后端处理通常要先将

echarts与mapbox-gl整合笔记

  1. echarts中所有地图类型都通过registerCoordinateSystem注册,所以,与mapbox-gl整合的时候也可通过它注册一个坐标系。

  2. 参考echartlayer发现echarts实例实际上并不是绘制到mapbox实例化的dom上,而是通过document.createElement('div')动态创建的一个dom,然后在上面实例化的,实例化后叠加在mapbox实例的上一层。通过偏移来保证两个坐标上的点能重合上。

js的模块化

AMD

CMD

import\export
import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
如果想为输入的变量重新取一个名字,import语句中要使用as关键字,将输入的变量重命名。

import *可以整体输入模块(可用import * as 给引入的模块重命名)
module命令可以取代import语句,达到整体输入模块的作用。
module命令后面跟一个变量,表示输入的模块定义在该变量上。

export default 就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。
例如输入jquery,可将jquery整个绑定到$上:
import $ from 'jquery';

RGB、RGBA、16进制、十进制、透明色

RGB:值在0-255范围变化,如红色rgb(255,0,0)
RGBA:比RGB多了一个透明通道,值在0-1之前,越小表示透明度越高,越看不见,如红色不透明rgba(255,0,0,1)
十六进制:以#开头,加六位值,每一位的值都在0-F范围变化,0最浅,F颜色最深,如红色,#FF0000
十六进制透明:与十六进制相似,但在#后多跟了两位值作为透明度,共9位,如红色完全透明,#00FF0000
十进制:这种应该不能使用
HSL:如,hsl(色调,饱和度,亮度),Hue 是色盘上的度数(从 0 到 360) - 0 (或 360) 是红色,120 是绿色,240 是蓝色。Saturation 是百分比值;0% 意味着灰色,而 100% 是全彩。Lightness 同样是百分比值;0% 是黑色,100% 是白色。hsl(120,65%,75%)
HSLA:与HSL模式类似,增加了透明度值,如hsla(120,65%,75%,0.3)

墨卡托与经纬度的转换

经度转墨卡托

function handle_x(x) {
 return (x / 180.0) * 20037508.34;
}

纬度度转墨卡托

function handle_y(y) {
 if (y > 85.05112) {
  y = 85.05112;
 }

 if (y < -85.05112) {
  y = -85.05112;
 }

 y = (Math.PI / 180.0) * y;
 var tmp = Math.PI / 4.0 + y / 2.0;
 return 20037508.34 * Math.log(Math.tan(tmp)) / Math.PI;

}

墨卡托转经度

function handle_me_x(x)
{
 return x/20037508.34*180;
}

墨卡托转纬度

function handle_me_y(my)
{
  var mmy = my/20037508.34*180;
  y= 180/Math.PI*(2*Math.atan(Math.exp(mmy*Math.PI/180))-Math.PI/2);
  return y;
}

webpack深入学习(一)sourcemap

devtool配置项很多, 但其实只是五个关键字eval,source-map,cheap,module,inline的任意组合。这五个关键字每一项都代表一个特性, 这四种特性可以任意组合

  • eval: 使用eval包裹模块代码(它的所有source都写在代码块内,并且用eval包裹,并不易于阅读,虽然效率很高)

  • source-map: 产生.map文件(我们打开调试查看代码的时候直接就是显示的source文件,易于查看和打断点调试)

  • cheap: 虽然有sourcemap方便调试,但错误只精确到行,不精确到列,也不包含loader的sourcemap

  • module: 包含loader的sourcemap(比如jsx to js ,babel的sourcemap)

  • inline: 将.map作为DataURI嵌入,不单独生成.map文件(这个配置项比较少见)

最终可以组合成的值有:

  • eval: 生成代码 每个模块都被eval执行,并且存在@sourceURL

  • cheap-eval-source-map: 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl

  • cheap-module-eval-source-map: 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能

  • eval-source-map: 原始代码 同样道理,但是最高的质量和最低的性能

  • cheap-source-map: 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用

  • cheap-module-source-map: 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射

  • source-map: 原始代码 最好的sourcemap质量有完整的结果,但是会很慢

参考资料Webpack中的sourcemap

加密通信rsa

用户登录和敏感信息传输的时候需要加密通信。

原理:
服务端生成一个公钥和一个私钥,
客户端请求时将公钥发送给客户端,
客户端用公钥对数据进行加密,
客户端将加密后的数据传输到服务器,
服务器用私钥对数据进行解密,得到真实数据。

这种加密只能保证数据传输过程中的安全性(不被修改伪造),不能保证客户端平台原始数据的安全性(不被查看内容)。
公钥不论是永久存储在客户端还是动态从服务端取都没有任何影响。
因为服务器下行数据时不会带有敏感数据,看了也无妨,客户端会验证数据的来源,不用担心数据被篡改过。

其它补充说明:
公钥和私钥是成对出现的,两者可相互解密。
通常来讲公钥是可以公开发放的,私钥只能一个人保存。
RSA公钥和私钥,私钥可以计算出公钥,公钥不能计算出私钥(至于怎么算的还不清楚...)。
私钥加密出的东西唯一,所以用公钥检验加密后的数据能用于判断一个人的身份唯一性。公钥用于加密上行的数据,保证只有私钥能解开结果。

实际运用中,服务器保存私钥,客户端保存公钥,客户端用公钥加密数据后向服务端传输以保证数据只能被有正确私钥的服务端解开,服务端用私钥加密数据传输给客户端,客户端通过公钥验证数据确实是有私钥的服务端发出来的没有被中间人修改过的。

那么多个客户端都有同一个公钥都能解析同一个私钥客户端发出来的数据?假如有坏人也拿到这个公钥看了我的数据怎么办?
简单说非对等加密真的只能保证服务端发出的数据没有被中间人修改,不能保证有公钥的恶意用户在传输过程中截取数据偷看内容。所以服务端下行传输通常不会传输敏感数据。
若非要做到下行数据也安全的话那只能客户端也生成一个自己的私钥,服务端下行发送数据时用客户端传给服务端的公钥进行加密,那就只能对应的客户端才能解开了。

库的使用:
github上star最多的库为jsencrypt

使用时可通过npm安装(虽然github上文档并没有提供这个方法)
直接引jsencrypt.min.js不行,原因未知。
import JsEncrypt from 'jsencrypt/bin/jsencrypt'

而且需要将jsencrypt压入到Vue才能正确使用,很奇特。
Vue.prototype.$jsEncrypt = JsEncrypt

使用时需要new一个对象出来。查看源码发现这个对象实质是用jsEncrypt下的JSEncrypt方法实例化的,所以。
new this.$jsEncrypt.JSEncrypt()

参考:
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
https://objc.cc/2017/07/26/Javascript%E5%BD%93%E4%B8%AD%E7%9A%84RSA%E5%8A%A0%E8%A7%A3%E5%AF%86/
https://github.com/travist/jsencrypt

JS的异步

异步编程要区分:

  • 首次加载
  • 全局依赖
  • 渐进加载
  • 结果缓存

ES7的异步写法虽然让代码看上去简洁了许多,但实际上要真正实现异步代码与同步代码混合编写还是很依赖于个人整体架构能力,否则代码依旧是一团遭。

async指定某函数内有异步
await指定执行需等待后面的结果返回后再向下执行。

await后的内容通常是个被Promise包裹的ajax。

await不使用then来处理结果就需要使用到try{要执行的await语句}catch(error){promise返回reject时需要执行的处理}来处理结果了。此方法将原来需要使用回调函数处理的代码改成了同步写法。

fetch和http2都只能支持到ie11+。ie系列都不支持,最低只能支持到edge。
fetch很好用,也可以设置跨域,返回的本身就是一个promise,所以处理起来比较方便。但是返回的数据格式好像需要result.json()这个函数来处理一下。

参考文献:快速理解和使用 ES7 await/async

每次封装Angular指令的时候都折腾好久,是时候总结一波了

Angular模块化主要有两种方式,一种是通过ui-router实现路由的方式,一种是通过directive封装指令的方式

先来谈谈指令吧
首先需要在appInit文件中将指令的bootstrap文件加载进项目,以启动相应的指令模块
然后在bootstrap文件中依次启动controller,directive,service
每个文件都是外层使用amd规范加载相应的DOJO模块,然后在内层再使用使用Angular的factory模式加入Angular的相关依赖。
service里面要有return

然后是指令传参的问题,
directive里有replace,它决定渲染的时候是否保留指令的原标签在dom中显示
restrict通常使用E(element)模式,这种模式兼容性最好,其次可以选用A(attribute)模式
最后是scope.它定义了父模块与子模块之前变量使用关系,
false:儿子继承父亲的值,改变父亲的值,儿子的值也随着改变,反之亦然,这就是继承且不隔离
true:儿子继承父亲的值,改变父亲的值,儿子的值也随着改变,但是改变儿子的值,父亲的值并没有改变,这就是继承但是隔离
{}:没有继承父亲的值,所以儿子的值为空,改变任何一方的值都不会影响另一方,这就是不继承且隔离

隔离状态下需要手动属性传参,=双向绑定,@单向绑定,
如在=,@后不跟属性名则默认与键名相同
这种方式只能传字符串型数据,不能传递对象等
指令调用处需要使用-来区分驼峰命名,其值直接是父模块$scope上的值,不需要使用{{}}
子模块接收时不用特意去接收,只需要直接在子模块使用$scope.指令(directive)中定义的属性名就可以了

再来补充路由吧

关于js中的数组

map方法:map(function(val,index){});第二个参数才是索引,这与jquery中的map相反

关于z-index

z-index有正有负,默认值为1,值越大越在上层,在嵌套的情况下,每个有z-index的元素都只相对于其父级元素,所以,有不同父级元素的两个有z-index的元素表现情况只取决于父元素的绘制层级,子元素设置的z-index值再大也不会影响它与另一个子元素的表现层级关系

cssText

当使用js修改元素样式时
传统方法为:

var element= document.getElementById(“id”);
element.style.width=”20px”;
element.style.height=”20px”;
element.style.border=”solid 1px red”;

cssText语法为:
obj.style.cssText=”样式”;

cssText会清除原来的所有模式,所以可以使用:

Element.style.cssText += ‘width:100px;height:100px;top:100px;left:100px;’
进行样式累加

但是,cssText(假如不为空)在IE中最后一个分号会被删掉

所以,可以在前面添加一个分号来解决这个问题:

Element.style.cssText += ‘;width:100px;height:100px;top:100px;left:100px;’

leaflet源码解析

代码组织结构

  • src/core/util.js为代码执行的最基础文件
  • 通过一个var同时声明多个变量时不要跨行才能保证代码简洁易读
  • getParamString将一个对象转换成url的字符串参数类型

编译流程

如何用Golang打开指定网页

如今前端技术已经有了巨大发展,
使用前端技术可以用很少的时间做出很好的交互
Golang又是一个编译极其简单的语言,且跨平台性能优秀
因此以后可以用本地网页的形式开发桌面程序的界面
那么首先要解决的就是Go语言打开网页的问题
实现原理大致是使用Go的核心库调用cmd,
通过cmd执行一个
C:\Windows\System32\rundll32.exe url.dll,FileProtocolHandler http://www.freesite.cc
这样的命令
不多说,直接上代码

package main

import (
	"os"
	"os/exec"
	"path/filepath"
)


func main() {
	var (
		cmd      = "url.dll,FileProtocolHandler"
		runDll32 = filepath.Join(os.Getenv("SYSTEMROOT"), "System32", "rundll32.exe")
	)
	exec.Command(runDll32, cmd, "http://www.freesite.cc").Start()
}

box-sizing

border-box:
为元素设定的宽度和高度决定了元素的边框盒。
就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。
通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。
ie

content-box:
宽度和高度分别应用到元素的内容框。
在宽度和高度之外绘制元素的内边距和边框。
w3规范

关于使用angular-ui-router的坑

在appInit.js文件导入router时一定要注意名字,在导入的路径处是以router结尾的模块名字,而在引入到项目中启动时又加了Provider这一 点点,如:appRouterProvider

PHP与websocket通信

<?php
class WS {
	var $master;
	var $sockets = array();
	var $debug = false;
	var $handshake = false;

	function __construct($address, $port){
		$this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)     or die("socket_create() failed");
		socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1)  or die("socket_option() failed");
		socket_bind($this->master, $address, $port)                    or die("socket_bind() failed");
		socket_listen($this->master,20)                                or die("socket_listen() failed");
		
		$this->sockets[] = $this->master;
		$this->say("Server Started : ".date('Y-m-d H:i:s'));
		$this->say("Listening on   : ".$address." port ".$port);
		$this->say("Master socket  : ".$this->master."\n");
		
		while(true){
			$socketArr = $this->sockets;
			$write = NULL;
			$except = NULL;
			socket_select($socketArr, $write, $except, NULL);  //自动选择来消息的socket 如果是握手 自动选择主机
			foreach ($socketArr as $socket){
				if ($socket == $this->master){  //主机
					$client = socket_accept($this->master);
					if ($client < 0){
						$this->log("socket_accept() failed");
						continue;
					} else{
						$this->connect($client);
					}
				} else {
					$this->log("^^^^");
					$bytes = @socket_recv($socket,$buffer,2048,0);
					$this->log("^^^^");
					if ($bytes == 0){
						$this->disConnect($socket);
					}
					else{
						if (!$this->handshake){
							$this->doHandShake($socket, $buffer);
						}
						else{
							$buffer = $this->decode($buffer);
							$this->send($socket, $buffer.'666'); 
						}
					}
				}
			}
		}
	}
	
	function send($client, $msg){
		$this->log("> " . $msg);
		$msg = $this->frame($msg);
		socket_write($client, $msg, strlen($msg));
		$this->log("! " . strlen($msg));
	}
	function connect($socket){
		array_push($this->sockets, $socket);
		$this->say("\n" . $socket . " CONNECTED!");
		$this->say(date("Y-n-d H:i:s"));
	}
	function disConnect($socket){
		$index = array_search($socket, $this->sockets);
		socket_close($socket);
		$this->say($socket . " DISCONNECTED!");
		if ($index >= 0){
			array_splice($this->sockets, $index, 1); 
		}
	}
	function doHandShake($socket, $buffer){
		$this->log("\nRequesting handshake...");
		$this->log($buffer);
		list($resource, $host, $origin, $key) = $this->getHeaders($buffer);
		$this->log("Handshaking...");
		$upgrade  = "HTTP/1.1 101 Switching Protocol\r\n" .
					"Upgrade: websocket\r\n" .
					"Connection: Upgrade\r\n" .
					"Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n\r\n";  //必须以两个回车结尾
		$this->log($upgrade);
		$sent = socket_write($socket, $upgrade, strlen($upgrade));
		$this->handshake=true;
		$this->log("Done handshaking...");
		return true;
	}

	function getHeaders($req){
		$r = $h = $o = $key = null;
		if (preg_match("/GET (.*) HTTP/"              ,$req,$match)) { $r = $match[1]; }
		if (preg_match("/Host: (.*)\r\n/"             ,$req,$match)) { $h = $match[1]; }
		if (preg_match("/Origin: (.*)\r\n/"           ,$req,$match)) { $o = $match[1]; }
		if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)) { $key = $match[1]; }
		return array($r, $h, $o, $key);
	}

	function calcKey($key){
		//基于websocket version 13
		$accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
		return $accept;
	}

	function decode($buffer) {
		$len = $masks = $data = $decoded = null;
		$len = ord($buffer[1]) & 127;

		if ($len === 126) {
			$masks = substr($buffer, 4, 4);
			$data = substr($buffer, 8);
		} 
		else if ($len === 127) {
			$masks = substr($buffer, 10, 4);
			$data = substr($buffer, 14);
		} 
		else {
			$masks = substr($buffer, 2, 4);
			$data = substr($buffer, 6);
		}
		for ($index = 0; $index < strlen($data); $index++) {
			$decoded .= $data[$index] ^ $masks[$index % 4];
		}
		return $decoded;
	}

	function frame($s){
		$a = str_split($s, 125);
		if (count($a) == 1){
			return "\x81" . chr(strlen($a[0])) . $a[0];
		}
		$ns = "";
		foreach ($a as $o){
			$ns .= "\x81" . chr(strlen($o)) . $o;
		}
		return $ns;
	}

	
	function say($msg = ""){
		echo $msg . "\n";
	}
	function log($msg = ""){
		if ($this->debug){
			echo $msg . "\n";
		} 
	}
}
	

new WS('localhost', 2234);
?>

参考:http://www.cnblogs.com/hustskyking/p/websocket-with-php.html
注意:需要配置php环境变量和打开php.ini中的socket相关扩展。

“多页面间数据同步”深入

有时同时打开了多个标签页,在多个标签页上都可以进行数据操作,而这一份数据存储由于多页面共享的需要存储在localStorage中,此时我们有两种方案保证多页面间的数据一致性:
1.使用onstorage事件监听,相当于当数据更新到localStorage中的时候做一次全局广播,相应的页面接收到广播后各自处理页面刷新即可。
2.使用visibilitychange方案,数据还是更新到localStorage中,只是更新后不广播,只有在需要使用的标签页激活时再重新获取数据刷新页面。

localStorage方案:
onstorage事件:Chrome 下必须由其他页面触发。IE,Firefox 可以本页面触发。(本以为可以用于多标签页间数据同步,结果只能其它)
visibilitychange事件:

document.addEventListener('visibilitychange', function() {
     console.log(222);
});

document.visibilityState:表示下面 4 个可能状态的值
hidden:页面在后台标签页中或者浏览器最小化
visible:页面在前台标签页中
prerender:页面在屏幕外执行预渲染处理 document.hidden 的值为 true
unloaded:页面正在从内存中卸载

在angular这种双向绑定的页面中可能需要$scope.$apply();手动刷新一下,因为Angular基于事件绑定,它并没有监听到onstorage事件

Google AppEngine初探

最开始使用AppEngine是新浪sae,可是用户量起来之后它就全面收费了。然后就没用了。
后来在配置翻墙时又一次接触到了Google AppEngine。比较良心的是它每天还有1G免费浏量。
翻墙是没配置成功,不过倒是借此机会了解到可以自己在上面搭建服务。
Google AppEngine地址:https://console.cloud.google.com/appengine/start?

不会用的可在右上角三个点号里面找到“尝试互动教程”,一步一步指导,多操作两次就会了。

平台可以有cloud shell可以在线编辑代码,也可以有上传下载代码包的方式操作代码。
编写好代码后在云端shell中执行:gcloud app deploy将代码部署到云端
在浏览器中访问:https://项目名称.appspot.com/就可以查看效果了

详情可参考文档:https://cloud.google.com/appengine/docs/flexible/php/quickstart

javaScript,我们真的需要闭包么?

作用域,原型链,闭包为javaScript的三大难点,
闭包很大作用场景就是在异步的时候保证我们能够正确地保存变量,
而实际上仔细究其原理会发现,只是变量在异步中不断地被修改,所以在异步请求回来的时候变量已经循环到n了,取到的值自然是n,
想到这里,其实处理办法就很明白了,闭包是通过立即执行的方式生成一个局部变量,那么我们也同样可以通过复制的形式在局部创建一个变量,由于传统赋值方式是引用方式赋值,所以传统“=”赋值不会成功,因为它一直使用的是同一个引用,
通过复制的方式生成一个本地变量就不是引用类型了,所以函数内的值不会根据循环变化 。
复制的方式有很多,比如改变类型,给数字型前面加个空格,通过各种函数转换,或者通过angular.copy.

SVN

使用Git虽然已是大势所驱,SVN仍占一席之地

SVN使用起来很简单,但是作为一个小程序员,项目不算特别大,用了一年多并没有使用到它的一些优秀的版本控制功能,那么,今天趁着工程打包的机会,重新整理一下代码管理思路。

svn上建的项目一般有三个目录:tag(在放版本)、trunk(存放主分支代码)、branch(存放bug修改和特性修改代码)
到要提交的文件夹上右键,选择svn,Branch/Tag,

将to path,修改为“/tag/你要存放的名称”(这里的tag目录一般是通过界面选择是切换不过去的,界面里点选只能在trunk目录下)

参考文章:
SVN trunk(主线) branch(分支) tag(标记) 用法详解和详细操作步骤

mapbox-gl使用source-map模式打包不能使用的问题

部署发现,使用mapbox-gl的项目在使用source-map模式build后并不能成功运行,会报Uncaught ReferenceError: n is not defined等奇怪错误。
而使用eval-source-map模式打包出来的代码则没有此问题。
那么问题来了。
source-map模式打包出来的代码sourcemap单独存放为一个文件,而eval-source-map模式打包出来的sourcemap打包在代码里,两个打包出来的有用代码体积相差巨大,实际生产中当然要使用source-map模式,并在部署的时候放弃.map文件

研究发现,mapbox-gl之所以在sourcemap模式下打包错误是因为uglify模块造成的错误。
使用如下代码即可解决此问题。

uglify({
sourceMap: true,
compress: {
warnings: false,
comparisons: false, // don't optimize comparisons
},
})

参考资料:mapbox/mapbox-gl-js#4359

php与mysql中timestamp字段的时间自动更新

在建数据库时设置字段类型为TIMESTAMP类型
默认值设置为CURRENT_TIMESTAMP并勾选ON UPDATE CURRENT_TIMESTAMP
php更新数据的时候不要传入这一列的数据即可保证这一列插入的是当前时间
若不勾选ON UPDATE CURRENT_TIMESTAMP则只会在创建数据的时候写入创建数据时的时间,不会在更新这一行数据的时候也更新该字段的时间。

console.不止有log

从入门到发现新大陆

自学js的问题就是只会用alert()调试。

在那个前后端混合,前端还在JQuery时代的时候,用alert并不会感觉有什么不妥。

但是到了SPA型应用,尤其是有大量object类型需要查看时问题就来了。

后来发现了console.log(),一直用了两年也没有再去探索过。

后来无意间又研究了一下console,除了console.log外,还发现了许多其它好用的命令。

console是一个浏览器实现的API,不是js提供的功能,所以不同的浏览器所带的功能可能有细微差异。

几个最常用的方法:

  • console.table()可以将数据以表格的形式直观的打印出来
  • console.profile()可以分析性能
  • console.time(name)、console.timeEnd()可记录中间这段代码的运行时间
  • console.trace()可以追踪函数的调用和执行过程
  • console.warn(object[, object...])可输出警告信息(黄颜色)
  • console.error()输出一条错误信息,就像控制台报错那种效果(红颜色)

Chrome71下console的所有方法

编号 名称 说明
1 log 以原对象的形式打印出数据
2 error 以红色文字输出数据
3 warn 以黄色文字输出数据
4 info 与log类似,以黑白色输出数据
5 table 以表格形式输出数组对象
6 assert 接收两个参数,若第一个参数返回为false时则输出第二个参数
7 clear 清空控制台的输出
8 context -
9 count 通常放在某个函数中,用于记录该函数被调用了多少次
10 countReset 重置某个计数器或全部计数器为0,若传入参数则重置这个计数器
11 debug 与log类似
12 dir 可以显示一个对象的所有属性和方法,在打印dom对象的时候替代log效果较好。
13 dirxml 显示xml或html的所有后代树结构
14 group 与groupCollapsed/groupEnd一起将大量输出信息进行分组
15 groupCollapsed 分组显示信息
16 groupEnd 结束分组显示信息
17 memory 是一个属性,不是方法。可以查看js引擎的内存使用情况
18 profile 与profileEnd结合进行性能分析,具体怎么用我也还没试过
19 profileEnd 结束性能分析
20 time 与timeEnd组合用于记录time到timeEnd之间所花费的时间
21 timeEnd 结束计时
22 timeLog 用于在time与timeEnd之间输出值
23 timeStamp -
24 trace 显示当前执行的代码在堆栈中的调用路径

参考:

你真的了解 console 吗https://segmentfault.com/a/1190000000481884

MDN console文档

http://wangdoc.com/javascript/features/console.html#consolelog%EF%BC%8Cconsoleinfo%EF%BC%8Cconsoledebug

使用省略号表示多余的文本

width:760px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;这几个属性缺一不可

overflow

visible:默认值。内容不会被修剪,会呈现在元素框之外。
hidden: 内容会被修剪,并且其余内容是不可见的。
scroll:内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto:如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
inherit:规定应该从父元素继承 overflow 属性的值。

text-overflow

clip:修剪文本。
ellipsis:显示省略符号来代表被修剪的文本。
string:使用给定的字符串来代表被修剪的文本。

white-space

normal:默认。空白会被浏览器忽略。
pre:空白会被浏览器保留。其行为方式类似 HTML 中的 <pre> 标签。
nowrap:文本不会换行,文本会在在同一行上继续,直到遇到 <br> 标签为止。
pre-wrap:保留空白符序列,但是正常地进行换行。
pre-line:合并空白符序列,但是保留换行符。
inherit:规定应该从父元素继承 white-space 属性的值。

outline定义元素的轮廓

outline与border类似,能给元素一个轮廓,但是轮廓在还在border更外一层
与border的区别:、

  1. 它不参与到文档流中,因此它出现或消失时不会影响文档流,即不会导致文档的重新显示。
  2. 轮廓可能不是矩形,但是它不能创建圆形轮廓,所以行内元素的轮廓可能不同于该元素的边框,利用轮廓,我们可以合并部分轮廓,创建一个连续但非矩形的形状。

outline:宽度 样式 颜色
样式: none | dottedd | dashed | solid | double | groove | ridge | inset | outset | inherit

网页设计中返回顶部的方法

<a href="javascript:scroll(0,0)">返回顶部</a>
通过使用window.onscroll = function(){}来监听滚动事件
document.documentElement.scrollTop||document.body.scrollTop获取滚动条位置

全屏显示网页

打开全屏代码:

function launchFullScreen(element) {  
   if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen();
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
    }
}

关闭全屏代码:

function cancelFullScreen() {  
   if (document.exitFullscreen) {
      document.exitFullscreen();
    } else if (document.msExitFullscreen) {
      document.msExitFullscreen();
    } else if (document.mozCancelFullScreen) {
      document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen();
    }
} 

可通过window.resize= function(){}来监听是否处理全屏状态切换
可通过对比要全屏的元素和window.document.fullscreenElement判断是否处理全屏状态

参考资料:让你的页面瞬间全屏

javaScript类

定义“类”的方法的时候,只需要声明class就可以了,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。

另外,方法之间不需要逗号分隔,加了会报错。

类有constructor函数,传入的值都需要绑定到this上去,实例化类的时候需要为类传入constructor的参数。

继承的时候需要有extends关键字,且子类构造函数里需要有super()方法,其参数为父类的构造函数参数

super关键字,它指代父类的实例(即父类的this对象)。

ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this) )。ES6的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。

redis学习(一环境配置)

redis window版本下载地址:
https://github.com/MicrosoftArchive/redis
在releases里面

先双击redis-server.exe运行redis服务,再双击redis-cli.exe运行redis客户端

在使用PHP调用时需要先安装PHP扩展,

下载地址:
https://github.com/phpredis/phpredis

目前也还没有windows版本,需要自己编译。还要装visual studio比较麻烦。暂时先放弃。

找到一个已经编译好的phpredis
下载地址:
https://github.com/phpredis/phpredis/downloads
这个下载地址版本比较全:
http://windows.php.net/downloads/pecl/releases/redis/
安装的时候一定要选对版本,x86的还是x64的。vc9还是vc11平台下编译的。在自己的php_info中查看
还有这个地址(这个可以用):
https://pecl.php.net/package/redis/2.2.7/windows

使用:
redis可以存储字符串,哈希、列表、集合、有序集合等

SET key value 设置指定 key 的值
GET key 可获取指定key的值
RDB数据持久化建议开启,它并不明显消耗性能,但能在redis崩溃掉后能快速重启,不需要完全重新导入数据

arcgis javascript在使用selectFeatures

arcgis javascript在使用selectFeatures时要设置symbol,否则选中时并没有实际效果
而在设置symbol时若只设置边的样式(SimpleLineSymbol)而不设置SimpleFillSymbol时,则点击的时候实际是获取不到节点的

深入理解JavaScript原型链

相信每个写脚本语言的同学都有一段不羁的情怀。

JavaScript是一门垃圾语言,即使是现在有了V8,有了Node.js,有了React,有了Vue,有了Angular。

然而它的简单,它的灵活让我入坑仍很欣慰。

一切因果皆由图起

原型链图片

学习原型链前我们有几个定理:

  1. 对象都有__proto__属性

  2. 函数都有prototype属性

  3. 对象的__proto__指向的是创建它的函数的prototype

  4. 函数是一种特殊的对象

  5. 对象由函数创建

可以总结出来的要点:

  1. Object.prototype.__proto__指向null

  2. Function.__proto__指向Function.prototype

  3. Object.__proto__指向Function.prototype

  4. Function.prototype.__proto__指向Object.prototype

  5. 即除Object.prototype指向null外其它对象的prototype都指向Object.prototype

  6. 查找对象属性时先查对象本身属性,再通过原型链__proto__向上查找属性

  7. Instanceof的判断队则是:沿着A的proto这条线来找,同时沿着B的prototype这条线来找,如果两条线
    能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false

下载canvas为本地图片

var img = map.getCanvas().toDataURL();
var a = document.createElement('a');
a.href=img;
a.target = '_blank';
a.download = 'downloadMap.png';
a.click();

注:mapbox中需要先在地图配置中设置preserveDrawingBuffer 参数为true,否则获取到的数据不正确

百度、火星坐标、wgs84相互转换

var pi = Math.PI,
	a = 6378245.0,
	ee = 0.00669342162296594323,
	x_pi = pi * 3000 / 180;

	
function outOfChina(lng, lat) {
	return (lng < 72.004 || lng > 137.8347) || (lat < 0.8293 || lat > 55.8271)
}


function transformLat(x, y) {
	var pi = Math.PI,
		ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
	ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
	ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
	ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
	return ret;
}


function transformLng(x, y) {
	var pi = Math.PI,
		ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
	ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
	ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
	ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
	return ret;
}


function checkCoordinate(lng, lat) {
	if (arguments.length === 1 && lng instanceof Array) {
		lat = +lng[1];
		lng = +lng[0];
	} else {
		lng = +lng;
		lat = +lat;
	}
	if (isNaN(lng) || isNaN(lat)) {
		throw new Error('Invalid parameters');
	}
	return [lng, lat];
}


/**
 * WGS84坐标转GCJ02坐标
 * @param {number|Array} lng 经度值或经纬度数组
 * @param {number} [lat] 纬度值
 * @returns {Array<number>} 转换后的GCJ02经纬度数组
 */
function wgs2gcj(lng, lat) {
	var coord = checkCoordinate(lng, lat),
		gLng, gLat;
	lng = coord[0];
	lat = coord[1];
	if (outOfChina(lng, lat)) {
		gLng = lng;
		gLat = lat;
	} else {
		var dLat = transformLat(lng - 105.0, lat - 35.0),
			dLng = transformLng(lng - 105.0, lat - 35.0),
			radLat = lat / 180.0 * pi,
			magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		var sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		gLat = lat + dLat;
		gLng = lng + dLng;
	}
	return [gLng, gLat];
}


/**
 * GCJ02坐标转WGS84坐标
 * @param {number|Array} lng 经度值或经纬度数组
 * @param {number} [lat] 纬度值
 * @returns {Array<number>} 转换后的WGS84经纬度数组
 */
function gcj2wgs(lng, lat) {
	if (outOfChina(lng, lat)) {
		return [lng, lat]
	}
	else {
		var dlat = transformLat(lng - 105.0, lat - 35.0);
		var dlng = transformLng(lng - 105.0, lat - 35.0);
		var radlat = lat / 180.0 * pi;
		var magic = Math.sin(radlat);
		magic = 1 - ee * magic * magic;
		var sqrtmagic = Math.sqrt(magic);
		dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
		dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
		mglat = lat + dlat;
		mglng = lng + dlng;
		return [lng * 2 - mglng, lat * 2 - mglat]
	}
}


/**
 * GCJ02坐标转百度BD09坐标
 * @param {number|Array} lng 经度值或经纬度数组
 * @param {number} [lat] 纬度值
 * @returns {Array<number>} 转换后的BD09经纬度数组
 */
function gcj2bd(lng, lat) {
	var coord = checkCoordinate(lng, lat),
		x = coord[0],
		y = coord[1],
		z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi),
		theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
	return [
		z * Math.cos(theta) + 0.0065,
		z * Math.sin(theta) + 0.006
	];
}


/**
 * 百度DB09坐标转GCJ02坐标
 * @param {number|Array} lng 经度值或经纬度数组
 * @param {number} [lat] 纬度值
 * @returns {Array<number>} 转换后的GCJ02经纬度数组
 */
function bd2gcj(lng, lat) {
	var coord = checkCoordinate(lng, lat),
		x = coord[0] - 0.0065,
		y = coord[1] - 0.006,
		z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi),
		theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
	return [
		z * Math.cos(theta),
		z * Math.sin(theta)
	];
}

var gcj = bd2gcj(106.55803,29.569023);
console.log(gcj);
//[106.5515951464041,29.562730117201024]
console.log(gcj2wgs(gcj[0],gcj[1]));
//[106.54787750396565,29.565578928729394]

经纬度转Web墨卡托

function LonLat2WebMercator(lng, lat) {
            var x = (lng / 180.0) * 20037508.3427892;
            var y;
            if (lat > 85.05112) {
                lat = 85.05112;
            }
            if (lat < -85.05112) {
                lat = -85.05112;
            }
            y = (Math.PI / 180.0) * lat;
            var tmp = Math.PI / 4.0 + y / 2.0;
            y = 20037508.3427892 * Math.log(Math.tan(tmp)) / Math.PI;
            var result = {
                x: x,
                y: y
            };
            return result;
 }

Web墨卡托转经纬度

function mercatorTolonlat(mercator){
    var lonlat={x:0,y:0};
    var x = mercator.x/20037508.34*180;
    var y = mercator.y/20037508.34*180;
    y= 180/Math.PI*(2*Math.atan(Math.exp(y*Math.PI/180))-Math.PI/2);
    lonlat.x = x;
    lonlat.y = y;
    return lonlat;
}

百度经纬度bd09II转百度墨卡托bd09mc

var LLBAND =[75, 60, 45, 30, 15, 0];
    var LL2MC = [
        [-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5],
        [0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5],
        [0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5],
        [0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5],
        [-0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5],
        [-0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45]
    ];
    function getRange(cC, cB, T) {
        if (cB != null) {
            cC = Math.max(cC, cB);
        }
        if (T != null) {
            cC = Math.min(cC, T);
        }
        return cC;
    }
    function getLoop(cC, cB, T) {
        while (cC > T) {
            cC -= T - cB;
        }
        while (cC < cB) {
            cC += T - cB;
        }
        return cC;
    }


    function convertor(cC, cD) {
      if (!cC || !cD) {
        return null;
      }
      let T = cD[0] + cD[1] * Math.abs(cC.x);
      const cB = Math.abs(cC.y) / cD[9];
      let cE = cD[2] + cD[3] * cB + cD[4] * cB * cB +
        cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB +
        cD[7] * cB * cB * cB * cB * cB +
        cD[8] * cB * cB * cB * cB * cB * cB;
      T *= (cC.x < 0 ? -1 : 1);
      cE *= (cC.y < 0 ? -1 : 1);
      return [T, cE];
    }


    function convertLL2MC(T) {
        let cD, cC, len;
        T.x = getLoop(T.x, -180, 180);
        T.y = getRange(T.y, -74, 74);
        const cB = T;
        for (cC = 0, len = LLBAND.length; cC < len; cC++) {
            if (cB.y >= LLBAND[cC]) {
                cD = LL2MC[cC];
                break;
            }
        }
        if (!cD) {
            for (cC = LLBAND.length - 1; cC >= 0; cC--) {
                if (cB.y <= -LLBAND[cC]) {
                    cD = LL2MC[cC];
                    break;
                }
            }
        }
        const cE = convertor(T, cD);
        return cE;
    }

百度墨卡托bd09mc转bd09II

var MCBAND = [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0];
    var MC2LL = [
      [1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 17337981.2],
      [-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 10260144.86],
      [-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37],
      [-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06],
      [3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4],
      [2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364, 826088.5]
    ];


    function convertor(cC, cD) {
      if (!cC || !cD) {
        return null;
      }
      let T = cD[0] + cD[1] * Math.abs(cC.x);
      const cB = Math.abs(cC.y) / cD[9];
      let cE = cD[2] + cD[3] * cB + cD[4] * cB * cB +
        cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB +
        cD[7] * cB * cB * cB * cB * cB +
        cD[8] * cB * cB * cB * cB * cB * cB;
      T *= (cC.x < 0 ? -1 : 1);
      cE *= (cC.y < 0 ? -1 : 1);
      return [T, cE];
    }
    

    function convertMC2LL(cB) {
      const cC = {
        x: Math.abs(cB.x),
        y: Math.abs(cB.y)
      };
      let cE;
      for (let cD = 0, len = MCBAND.length; cD < len; cD++) {
        if (cC.y >= MCBAND[cD]) {
          cE = MC2LL[cD];
          break;
        }
      }
      const T = convertor(cB, cE);
      return T;
    }

度分秒转十进制度

const data = [
    [`105°53'33.7056"`, `28°55'33.7007"`],
    [`105°50'48.3423"`, `28°56'42.5295"`],
    [`105°50'13.5311"`, `28°56'39.7392"`],
    [`105°49'19.8841"`, `28°56'42.5295"`],
    [`105°49'59.5704"`, `28°57'55.2528"`],
    [`105°51'7.0272"`, `28°59'32.2332"`],
    [`105°51'23.5979"`, `29°1'18.1812"`],
    [`105°51'27.6408"`, `29°1'22.206"`],
    [`105°52'37.2144"`, `29°1'55.4988"`],
    [`105°52'47.9216"`, `29°2'41.8178"`],
    [`105°52'47.9216"`, `29°2'40.4268"`],
    [`105°53'42.3707"`, `29°3'6.6960"`],
    [`105°55'49.7100"`, `29°3'31.2767"`],
    [`105°56'26.5847"`, `29°3'41.9652"`],
    [`106°4'38.4924"`, `29°5'0.6828"`],
    [`106°4'12.8604"`, `29°5'23.1468"`],
    [`106°6'46.4364"`, `29°3'39.3372"`],
    [`106°8'22.3727"`, `29°4'20.3124"`],
    [`106°8'59.4456"`, `29°12'24.5160"`],
    [`106°13'19.9487"`, `29°12'37.4292"`],
    [`106°14'3.6528"`, `29°14'31.0775"`],
    [`106°15'32.0663"`, `29°17'41.3084"`],
    [`106°19'51.222"`, `29°15'30.1644"`],
    [`106°23'41.5788"`, `29°17'37.5935"`],
    [`106°23'39.5808"`, `29°20'27.4199"`]
]

function DegreeConvertBack(value) { ///<summary>度分秒转换成为度</summary>
    var du = value.split("°")[0];
    var fen = value.split("°")[1].split("'")[0];
    var miao = value.split("°")[1].split("'")[1].split('"')[0];

    return Math.abs(du) + (Math.abs(fen) / 60 + Math.abs(miao) / 3600);
}

const arr = []
let stringsx = '';
let stringsy = '';
data.map(v => {
    const result = []
    v.map(a => {
        result.push(DegreeConvertBack(a))
    })
    arr.push(result)
    stringsx += result[0]+'\r\n';
    stringsy += result[1]+'\r\n';
})

console.log(stringsx);
console.log(stringsy);

参考

https://blog.csdn.net/qq_35771567/article/details/84766271

在echart-gl中获取mapbox实例并操作

最开始通过分析元素得出的笨办法:
var com = myChart['_componentsMap'];
for(var i in com){
if(i.indexOf('mapbox')!=-1){
var mapbox = com[i]['_zrLayer'].getMapbox();
console.log(mapbox);
mapbox.setZoom(17);
break;
}
}

myChart为echart-gl实例

后来官方推荐的办法:
var mapbox = myChart.getModel().getComponent('mapbox3D').getMapbox();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.